Какова должна быть стратегия поблочного тестирования при использовании МОК?

В конце концов, что я считал о Внедрении зависимости и МОК, я решил попытаться использовать Виндзорский Контейнер в рамках нашего приложения (это - 50K LOC многослойное веб-приложение, таким образом, я надеюсь, что это не излишество там). Я использовал простой статический класс для обертывания контейнера, и я инициализирую его при запуске приложения, которое работает довольно прекрасное на данный момент.

Мой вопрос о поблочном тестировании. Я знаю, что DI собирается сделать мою жизнь намного легче там путем предоставления мне возможности введения тупика / ложные реализации сотрудников класса к классу под тестом. Я уже записал несколько тестов с помощью этой техники, и это, кажется, имеет смысл для меня. То, в чем я не уверен, - должен ли я использовать МОК (в этом случае, Виндзорский замок) также в модульных тестах (вероятно, так или иначе настраивают его для возврата тупиков / насмешки для моих особых случаев), или это лучше для проводного соединения всех зависимостей вручную в тестах. Что Вы думаете и какая практика работала на Вас?

16
задан alexandrul 19 May 2010 в 09:31
поделиться

4 ответа

Вам не нужен DI контейнер в модульных тестах, потому что зависимости предоставляются через mock объекты, созданные с помощью таких фреймворков, как Rhino Mocks или Moq. Так, например, когда вы тестируете класс, который зависит от какого-то интерфейса, эта зависимость обычно обеспечивается через инъекцию конструктора.

public class SomeClassToTest
{
    private readonly ISomeDependentObject _dep;
    public SomeClassToTest(ISomeDependentObject dep)
    {
        _dep = dep;
    }

    public int SomeMethodToTest()
    {
        return _dep.Method1() + _dep.Method2();
    }
}

В вашем приложении вы будете использовать DI-фреймворк для передачи некоторой реальной реализации ISomeDependentObject в конструкторе, который сам может иметь зависимости от других объектов, в то время как в модульном тесте вы создаете объект-макет, потому что вы хотите тестировать этот класс только изолированно. Пример с Rhino Mocks:

[TestMethod]
public void SomeClassToTest_SomeMethodToTest()
{
    // arrange
    var depStub = MockRepository.CreateStub<ISomeDependentObject>();
    var sut = new SomeClassToTest(depStub);
    depStub.Stub(x => x.Method1()).Return(1);
    depStub.Stub(x => x.Method2()).Return(2);

    // act
    var actual = sut.SomeMethodToTest();

    // assert
    Assert.AreEqual(3, actual);
}
20
ответ дан 30 November 2019 в 21:36
поделиться

Я работаю над проектом ASP.NET MVC с примерно 400 модульными тестами. Я использую Ninject для внедрения зависимостей и MBUnit для тестирования.

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

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

Я также имитирую объекты (в отличие от подделки) в некоторых тестах, но я обнаружил, что подделка репозиториев данных приводит к меньшему количеству работы и более точным тестам.

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

Вначале это было довольно сложно настроить, но это действительно помогло мне сэкономить много времени в долгосрочной перспективе.

3
ответ дан 30 November 2019 в 21:36
поделиться

Я только что написал приложение очень похожего стиля и размера. Я бы не стал включать инъекцию зависимостей в модульные тесты, потому что это не настолько сложно, чтобы быть необходимым. Вы должны использовать фреймворк для создания моков (RhinoMocks / Moq).

Также Automocking в Moq или Auto Mock Container в Rhinomocks еще больше упростят создание ваших моков.

Автомокинг позволяет вам получить объект того типа, который вы хотите протестировать, без создания моков вручную. Все зависимости высмеиваются автоматически (предполагается, что они являются интерфейсами) и инжектируются в конструктор типа. Если вы можете задать ожидаемое поведение, но это не обязательно.

2
ответ дан 30 November 2019 в 21:36
поделиться

Как уже указал Дарин, вам не нужно использовать DI, если у вас есть моки. (Однако у DI есть и несколько других преимуществ, включая, прежде всего, уменьшение зависимостей в вашем коде, что значительно упрощает поддержку и расширение вашего кода в долгосрочной перспективе.)

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

0
ответ дан 30 November 2019 в 21:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: