2010-11-24 6 views
6

Я использую контейнер DI, и я хочу выполнить модульные тесты MSTest (VS 2010) с экземплярами, разрешенными из контейнера.MSTest TestMethod Injection Dependency

Я бы хотел, чтобы эти экземпляры были введены в мой TestMethod или по крайней мере мой TestClass. Это возможно?

Прямо сейчас мой метод TestMethods напрямую вызывает container.Resolve<T>(xxx), который я бы предпочел избежать, чтобы мое тестирование на вливание было более реалистичным.

У кого-нибудь есть опыт?

Заранее спасибо.

ответ

6

Создание экземпляра тестового класса происходит глубоко во внутренних классах структуры MSTest, поэтому вложение зависимостей в него было бы сложной задачей.

5

Основная причина - для написания кода в соответствии с шаблоном Injection Dependency и с использованием инфраструктур IoC - получить тестовый код. Однако использование контейнера IoC в тестовом коде приведет к противоположному результату. Из вашего вопроса я вижу, что вы уже это испытываете.

Это особенно проблема при использовании шаблона Service Locator (SL) вместо шаблона впрыска зависимостей (DI). С помощью шаблона SL класс вызывает контейнер IoC (или абстракцию такого контейнера) напрямую, вместо того, чтобы снабжать класс необходимыми ему зависимостями (используя инъекцию конструктора). Поскольку классы вызывают контейнер напрямую, вам необходимо настроить этот контейнер в тестовой среде. Это болезненно, потому что тестовая конфигурация или поддельные объекты часто становятся очень сложными, потому что вы часто хотите влиять на поведение подделки на каждой тестовой основе, сохраняя при этом все потокобезопасность, потому что тестовые среды могут запускать ваши тесты параллельно (MSTest делает это). Я знаю, что в прошлом я написал какой-то сумасшедший тестовый код с потоком, прежде чем я узнал, что делаю все это неправильно :-(.

Таким образом, вы должны использовать шаблон DI в своем коде приложения и в своих тестах необходимо связать эти зависимости вручную. Например, при тестировании класса HomeController, который зависит от класса ICustomerService, в вашем тестовом классе обычно должен быть фабричный метод CreateController() или CreateValidController, который централизует создание этого HomeController. Это избавит вас от записывая эти зависимости в каждом тесте и тем самым создавая кошмар для обслуживания в вашем тестовом коде. В этом заводском методе вы вводите, например, класс FakeCustomerService вручную, выполнив что-то вроде этого:

private static HomeController CreateController(
    InMemoryDataMapper mapper) 
{ 
    var uowFactory = new FakeNorthwindUnitOfWorkFactory() 
    { 
     UnitOfWork = new NorthwindUnitOfWork(mapper); 
    }; 

    return new HomeController(new FakeCustomerService(uowFactory)); 
} 

Как выглядит такой заводской метод, конечно, зависит от того, как выглядит структура зависимостей HomeController.

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

+0

Я не использую шаблон SL, к счастью ... только инжектор конструктора. Я подумал, что я помню, как я искал этот точный вопрос о параллельных тестах, потому что у меня была такая же озабоченность и видение, что MSBuild не запускает тесты параллельно по умолчанию, но я, вероятно, ошибаюсь. – Jeff 2010-11-24 19:03:16