2014-12-12 3 views
1

У нас есть приложение WPF. Многие из ViewModels используют те же зависимости, которые нужно издеваться. Иногда конструкторы ViewModels имеют слишком много зависимостей (over-injection), подверженных единственному намерению - разрешить модульное тестирование. Например:Как правильно использовать IoC в модульных тестах?

[ImportingConstructor] 
public PasswordInputViewModel(
    IPaymentSystemProvider provider, 
    IAppContext appCtx, 
    IEventAggregator eventAggregator, 
    IPromptCreator promptCreator) { 
} 

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

Из-за этого мы перешли эту зависимость в BaseViewModel класс:

public class ScreenExtended : Screen { 
    [Import] 
    public IEventAggregator eventAggregator { get; private set; } 

    [Import] 
    public IPromptCreator Prompt { get; private set; } 

    [Import] 
    public IAppContext CurrentApp { get; private set; } 
} 

Теперь нам нужно издеваться над ними как-то из модульных тестов, уклоняющихся инъекцию конструктора. Итак, мы можем загружать IoC.

И теперь возникает вопрос: Как правильно использовать IoC здесь? Загрузите IoC для каждого класса или для каждого теста или сделайте его статическим и инициализируйте только один раз? Если мы сделаем это статичным, нам нужно как-то перекомпоновать IoC. Чтобы вы посоветовали?

ответ

1

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

Я обычно повторно инициализирую каждую из зависимостей за тест, даже один конкретный класс (который издевается над сервисным слоем поверх ложного хранилища). При тестировании функциональности типа CRUD он определенно помогает сбрасывать до нуля каждый тест, несмотря на то, что он занимает немного больше времени. Скорее, у вас есть тест, который может выполняться корректно и надежно изолированно или в списке.

+0

Итак, когда вы пишете модульные тесты, вы повторно инициализируете IoC для каждого теста, правильно? Или вы просто удаляете предыдущего исполнителя зависимости и добавляете новый? – EngineerSpock

+0

Повторное инициализация контейнера каждый тест, да. – toadflakz

+0

Вы отдыхаете на собственном опыте и практике, или вы видели где-то, может быть, лучшие практики? Насколько я понимаю, у загрузочного устройства IoC в ваших модульных тестах есть несколько методов, благодаря которым вы можете передавать свои макеты и пару таких методов, как «Создать и отменить», да? – EngineerSpock

0

Иногда конструкторы ViewModel s имеют слишком много зависимостей (чрезмерной инъекции) с единственным намерением - разрешить модульное тестирование.

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

В контексте предоставленного ViewModel, имеет ли 4 зависимости нарушение? Этот вопрос не имеет правильного ответа (т. Е. Субъективного вопроса). Должен быть баланс зависимости: не слишком мало, не слишком много.

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

Рекомендация для обеспечения единого принципа ответственности довольно абстрактно, потому что больше ViewModel -классов должны видеть (их использование зависимостей): ввести уровень абстракции для инкапсулирования осуществления операций высокого уровня. Это может звучать слишком «большой», но это может быть просто «Фасад», который скрывает детали реализации операций высокого уровня (с использованием служб инфраструктуры и т. Д.).

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

Просьба рассмотреть возможность использования инжекции конструктора и реализации модульных испытаний без использования конкретного API-интерфейса DI-контейнера, если только это не требуется. Единичные тесты не должны зависеть от API конкретного DI-контейнера.