2015-12-14 3 views
2

Я не уверен, что то, что я делаю, на самом деле является «правильным» способом проведения модульных тестов с помощью DI. Прямо сейчас я прошу свой ViewModelLocator фактически создать все экземпляры, которые мне нужны, и просто получить экземпляр, который мне нужно протестировать, что очень просто проверить один экземпляр, поскольку позволяет предположить, что квитанция нуждается в создании объекта реселлера, который необходим реселлеру пользовательский объект, который должен быть создан, пользователю нужен какой-то другой объект, который будет создан, что создает цепочку объектов для создания только для проверки одного экземпляра.Неплохая идея использовать объекты инъекции зависимостей в модульных тестах?

С интерфейсами di usally будут издеваться и разбираться с объектом, который вы хотели бы создать, но как насчет простых объектов/ViewModels?

Какова наилучшая практика проведения модульных испытаний с участием DI?

public class JournalTest 
{ 
    private ReceiptViewModel receipt; 
    private ViewModelLocator locator; 
    [SetUp] 
    public void SetUp() 
    { 
     locator = new ViewModelLocator(); 

     receipt = SimpleIoc.Default.GetInstance<ReceiptViewModel>(); 
    } 
    [TearDown] 



    [Test] 
    public void CheckAndCreateNewJournal_Should_Always_Create_New_Journal() 
    { 
     receipt.Sale.Journal = null; 
     receipt.Sale.CheckAndCreateNewJournal(); 
     Assert.NotNull(receipt.Sale.Journal); 
    } 

} 
+0

Мне любопытно, почему ваша бизнес-логика позволяет установить «Журнал» в «null» и иметь «метод инициализации» 'CheckAndCreateNewJournal()'?Либо ваш журнал является обязательным, и вы инициализируете пустой журнал в своем конструкторе Sale (предпочтительно в поле для чтения в режиме чтения) и гарантируете его инвариантность, или вы создаете и возвращаете его, когда впервые вызывается getterGenerator, если поле поддержки 'null', но тогда вы не можете гарантировать, что инварианты класса. Инициализаторы - это запах кода и намек на плохой дизайн API – Tseng

ответ

2

Во-первых, вы не используете инъекции зависимостей в своем коде. То, что у вас там, называется Service Locator (локаторы службы создают плотную связь с IoC/Service Locator и затрудняют тестирование).

И да, это плохо (как локатор сервисов, так и инъекция зависимостей), потому что это означает: вы не выполняете UnitTest, вы проводите интеграционный тест.

В вашем случае ReceiptViewModel не будет протестирован отдельно, но ваш тест также проверяет зависимости ReceiptViewModel (т. Е. Репозиторий, услуги, вводимые и т. Д.). Это называется интеграционным тестом.

A UnitTest должен проверить только класс, о котором идет речь, и нет зависимостей. Вы можете добиться этого либо с помощью заглушек (фиктивная реализация ваших зависимостей, предполагая, что вы использовали интерфейсы в качестве зависимостей), либо с помощью mocks (с каркасом Mock, таким как Moq).

Это проще и лучше, поскольку вам не нужно реализовывать весь класс, но просто нужно настроить mocks для методов, которые вы знаете, которые понадобятся для вашего тестового примера.

В качестве дополнительной заметки вы должны создать себя. В зависимости от вашей инфраструктуры UnitTest могут проводиться тесты, управляемые данными (через атрибуты по методу тестирования), или вы просто создаете их в коде, или если у вас есть модели/сущности, используемые во многих классах, создайте для него вспомогательный метод.

Просмотр моделей не следует вводить в конструктор (по крайней мере, избегать), так как он их пары плотно

+0

как вы хотите использовать заглушки/макеты без их инъекции? Инъекционная инъекция идеально подходит для модульного тестирования. –

+0

Вы создаете макет и передаете макет в конструкторе. Это все еще инъекция, но не инъекция инъекций (где контейнер вводит конкретные типы), просто ручная инъекция, как в IoC – Tseng

+0

ну, для меня это все еще зависимость, но просто ручная –

0

Единицы испытания должны работать быстро и должен быть детерминированным. Это означает, что вы должны издеваться/заглушить все, что нарушает эти два правила.

Лучший способ издеваться/заглушки - это ввести их. В производстве классы собираются каркасом DI, но в модульных тестах вы должны собирать их вручную и при необходимости вводить макеты.

Существует также классический подход к тестированию, когда вы заглушаете/издеваетесь над каждой зависимостью вашего класса, но это бесполезно, поскольку вы ничего не получаете от этого. Martin Fowler написал отличную статью об этом: link Вы также должны прочитать Растущее объектно-ориентированное программное обеспечение: руководствуется тестами. Тон полезных знаний.

Смежные вопросы