Использование IoC для модульного тестирования

Как можно использовать контейнер IoC для модульного тестирования? Полезно ли управлять макетами в огромном решении (50+ проектов) с помощью IoC? Любой опыт? Любые библиотеки С#, которые хорошо работают для использования в модульных тестах?

Ответ 1

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

Рассмотрим класс, в котором используется инжектор конструктора

public MyClass(IMyDependency dep) { }

В вашем полном приложении может быть, что существует огромный график зависимостей за IMyDependency, но в unit test вы сглаживаете все это до одного Test Double.

Вы можете использовать динамические макеты, такие как Moq или RhinoMocks, для генерации Test Double, но это не требуется.

var dep = new Mock<IMyDependency>().Object;
var sut = new MyClass(dep);

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

Ответ 2

Как можно использовать контейнер Ioc для модульного тестирования?

IoC обеспечит применение парадигм программирования, которые упростят единичное тестирование (т.е. использование mocks): использование интерфейсов, никаких новых(), без синглотонов...

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

Полезно ли управлять mocks в огромном решении (50+ проектов) с помощью IoC?

Я не уверен, что вы подразумеваете под управлением mocks с помощью IoC. В любом случае, контейнеры IoC обычно могут делать больше, чем просто инъекции макетов, когда дело доходит до тестирования. И если у вас есть достойная поддержка IDE, которая делает рефакторинг возможной, почему бы не использовать его?

Любой опыт?

Да, на огромном решении вам нужно больше, чем когда-либо, решение, не подверженное ошибкам и рефакторингу (например, через безопасный контейнер типа IoC или хорошую поддержку IDE).

Ответ 3

Я часто использую контейнер IoC в своих тестах. Конечно, они не "модульные тесты" в чистом смысле. ИМО Они больше BDDish и облегчают рефакторинг. Тесты там, чтобы дать вам уверенность в рефакторе. Плохо написанные тесты могут быть похожи на заливку цемента в ваш код.

Рассмотрим следующее:

[TestFixture]
public class ImageGalleryFixture : ContainerWiredFixture
{
    [Test]
    public void Should_save_image()
    {
        container.ConfigureMockFor<IFileRepository>()
            .Setup(r => r.Create(It.IsAny<IFile>()))
            .Verifiable();

        AddToGallery(new RequestWithRealFile());

        container.VerifyMockFor<IFileRepository>();
    }

    private void AddToGallery(AddBusinessImage request)
    {
        container.Resolve<BusinessPublisher>().Consume(request);
    }
}

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

При использовании этой техники может понадобиться расширение автомозаичного контейнера: http://www.agileatwork.com/auto-mocking-unity-container-extension/

Ответ 4

Использование контейнеров с возможностью разрешения незарегистрированных/унаследованных сервисов, таких как SimpleInjector, DryIoc (его шахта) может возвращать mocks для еще не реализованных интерфейсов.

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