Разрешение инъекций зависимостей и модульное тестирование


Я пытаюсь изучить инъекцию зависимостей и столкнулся с проблемой при модульном тестировании приложения.

Я пишу консольное приложение, и контейнер создается и инициализируется в Main (), он доступен как get-property в Program.Container, поэтому в любом месте моего приложения я могу вызвать Program.Container.Resolve<..>().

У меня есть класс ServiceValidator, подобный этому:

public class ServiceValidator
{
    private readonly IConfiguration _configuration;
    private readonly IService _service;

    public ServiceValidator(IConfiguration configuration, IService service)
    {
        _configuration = configuration;
        _service = service;
    }

В другом классе я использую

ServiceValidator serviceValidator = Program.Container.Resolve<ServiceValidator>();
serviceValidator.VerifyVersion();

Это вызов Program.Container.Resolve, который вызывает у меня проблемы в модульном тесте, как это не было установка.

Разве это плохая практика-вызывать resolve на контейнере? Я мог бы создать экземпляр ServiceValidator в Main() и передать объект, но это кажется глупым, так как это вызовет множество параметров для объектов, которые просто передаются следующему методу.

Поэтому я думаю, что допустимо вызывать Resolve в классе, но тогда контейнер должен быть настроен для модульного теста. Как я должен это сделать, должен ли я переместить контейнер в другое место, чем программа класс? Что бы вы посоветовали?

Если это имеет значение, я использую Unity и C#

Спасибо : -)

5 6

5 ответов:

Разве это плохая практика-вызывать resolve на контейнере? Я мог бы создать экземпляр ServiceValidator в Main() и передать объект, но это кажется глупым, так как это вызовет множество параметров для объектов, которые просто передаются следующему методу.

Если вы используете инъекцию зависимостей полностью, то вам не нужно будет передавать множество параметров объектам. Конструктор каждого объекта должен иметь в качестве параметров только те зависимости, которые он сам использует напрямую - он не будет знать о транзитивных зависимостях своих прямых зависимостей.

Таким образом, если у вас есть класс X, который требует ServiceValidator, то класс X будет иметь параметр конструктора типа ServiceValidator. Тогда, если какой-то класс Y использует класс X, то класс Y будет иметь параметр конструктора типа X. обратите внимание, что Y ничего не знает О ServiceValidator, поэтому вам не нужно передавать ServiceValidator из одного класса в другой - единственное место, где он используется это при построении X, и это часто делается с помощью DI-фреймворка или только в одном месте на рукописной фабрике.

Некоторые ссылки для получения дополнительной информации:

Обычно я разрешаю вызовы для разрешения зависимостей от контейнера в таких местах, как main, хотя я все еще стараюсь свести их к минимуму. Затем я настраиваю контейнер в методе инициализации тестового класса. Я инициализировал его с помощью поддельных реализаций для любого тестового класса, который должен вызвать контейнер.

Тестовые классы, которые не вызывают ничего, требующего инициализации контейнера, могут игнорировать его и не использовать подделки. Я обычно использую насмешки в таких случаях. экземпляры.

Я также использую Microsoft Service Locator , так что зависимость, которую я беру, зависит от чего-то из .NET Framework, а не от конкретного контейнера. Это позволяет мне в будущем использовать все, что я хочу, даже домашний контейнер.

В качестве инициализатора контейнера можно использовать статический класс. Что-то вроде загрузчика.КС будет в порядке. Затем можно ссылаться на методы класса как в коде, так и в тестах.

Ну, то, что вы технически делаете, - это расположение службы в вашем классе.

Я помню, что читал эту статью некоторое время назад:

Http://martinfowler.com/articles/injection.html

Для моих классов я никогда не пытаюсь использовать Resolve в них. Я создаю объекты через контейнер, когда они мне нужны. Для модульного тестирования я либо использую некоторые фиктивные библиотеки и тупиковые классы.

Проблема заключается в том, что вы пытаетесь протестировать основной метод. Этот метод практически не поддается юнит-тестированию.

Я бы сказал, что лучше не тестировать ваш основной метод, потому что:

  • акцент в современном модульном тестировании делается на дизайне
  • Вы должны минимизировать зависимость от конфигурации в модульных тестах. Конфигурация может быть протестирована с помощью дымовых или интеграционных тестов.