Модульные тесты и инкапсуляция - PullRequest
0 голосов
/ 20 февраля 2019

Например, у меня есть класс, работающий с HttpClient

public class DomainActions : IDomainActions
{
    private readonly HttpClient _client;
    private readonly IConfiguration _configuration;

    public DomainActions(IConfiguration configuration)
    {
        _configuration = configuration;
        _client = new HttpClient()
        {
            BaseAddress = new Uri(_configuration.GetSection("DomainRegistration:BaseAddress").Value)
        };
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _configuration.GetSection("DomainRegistration:Token").Value);
    }

    public async Task<List<DomainDto>> GetDomainListAsync()
    {
        var responseMessage = await _client.GetAsync("domains");
        return await ProcessingDomainListResponseAsync(responseMessage);
    }

, затем мы решаем его следующим образом:

    services.AddTransient<IConfiguration>(....);
    services.AddTransient<IDomainActions, DomainActions>();

и класс клиента:

public class AddMxRecordToRegistrator
{
    protected readonly IDomainActions domainActions;
    public AddMxRecordToRegistrator(IDomainActions domainActions )
    {
        this.domainActions = domainActions ;
    }

    public async Task CreateDomainRecordAsync()
    {
            await domainActions.CreateDomainRecordAsync(queueItem.DomainForRegistration.DomainName, new DomainRegistrationCore.Models.DomainRecordDto
            {
                Content = queueItem.MxRecord,
                Name = String.Empty,
                Priority = 0,
                Ttl = 3600,
                Type = DomainRecordType.MX.ToString(),
                Regions = null
            });

хорошо, все работает нормально.

Сейчас я хочу создать модульный тест для класса AddMxRecordToRegistrator, но я не хочу использовать настоящий httpClient.Как это сделать?Конечно, я могу добавить еще одну зависимость:

public class DomainActions : IDomainActions
{
    private readonly HttpClient _client;
    private readonly IConfiguration _configuration;

    public DomainActions(IConfiguration configuration, HttpMessageHandler httpMessageHandler)
    {
        _configuration = configuration;
        _client = new HttpClient(httpMessageHandler)
        {
            BaseAddress = new Uri(_configuration.GetSection("DomainRegistration:BaseAddress").Value)
        };
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _configuration.GetSection("DomainRegistration:Token").Value);
    }


    public DomainActions(IConfiguration configuration) : this(configuration, new HttpClientHandler())
    {
    }

    public async Task<List<DomainDto>> GetDomainListAsync()
    {
        var responseMessage = await _client.GetAsync("domains");
        return await ProcessingDomainListResponseAsync(responseMessage);
    }

, затем изменить корень композиции DI:

    services.AddTransient<IConfiguration>(....);
    services.AddTransient<HttpMessageHandler>(....);
    services.AddTransient<IDomainActions, DomainActions>();

, но тогда почему клиентская часть (в нашем корне композиции случая) должна знать что-либо овнутренняя деталь DomainActions только потому, что нам нужно создать юнит-тест?Как будто мы нарушаем инкапсуляцию для юнит-тестов.Как правильно это реализовать?

Ответы [ 2 ]

0 голосов
/ 20 февраля 2019

но тогда почему клиентская часть (в нашем корне композиции) должна знать что-либо о внутренних деталях DomainActions только потому, что нам нужно создать модульный тест?

Корень композиции находится только вПриложение, которое будет «знать» обо всех зависимостях нижнего уровня.
Роль «Композиция» корня состоит в том, чтобы создавать необходимые классы с реализациями времени выполнения.

Класс AddMxRecordToRegistrator явно зависит от абстракции IDomainActions, поэтому для модулятестируя AddMxRecordToRegistrator, вы просто проходите ложную реализацию IDomainActions.

0 голосов
/ 20 февраля 2019

Чтобы расширить комментарий из @CamiloTerevinto, AddMxRecordToRegistrator должен зависеть от IDomainActions через внедрение зависимостей, то есть этот интерфейс должен быть аргументом, передаваемым его конструктору.

С точки зрения инкапсуляции, AddMxRecordToRegistrator не должен знать, что DomainActions зависит от IConfiguration или HttpMessageHandler.Он даже не должен знать, что DomainActions существует, потому что это конкретный класс, а AddMxRecordToRegistrator должен зависеть от интерфейсов, а не от конкретных классов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...