Автомок при помощи AutoFixture

Posted by PDSW on Saturday, October 27, 2018
Last Modified on Monday, February 11, 2019

TOC

Исходя из того что теперь вы знаете что такое авто-мок, хочу Вас обрадовать ещё одной штукой: AutoFixture - библиотекой разработанной Mark Seemann-ом которая предоставляет функционал автомока. О том как им воспользоваться и будет этот перевод статьи с блога автора.

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

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

Имейте в виду, что сборка AutoFixture сама по себе не зависит от Moq. Если вы не хотите использовать Moq, вы можете просто игнорировать сборку AutoFixture.AutoMoq.

В Auto-mock из AutoFixture не обязательно использовать Moq. Хотя он поставляется с поддержкой Moq, можно написать расширение для другой библиотеки динамических моков.

Чтобы использовать его, вы должны сначала добавить ссылку на AutoFixture.AutoMoq. Теперь вы можете создать свой экземпляр Fixture следующим образом:

var fixture = new Fixture()
    .Customize(new AutoMoqCustomization());

Этот код добавляет новый функционал в Fixture. Если тип проваливается через обычный Fixture-движок без обработки, расширение auto-mock проверяет, нужны ли этому типу сущьности интерфейсов или абстрактных классов. Если это так, он будет делегировать этот запрос на запрос Mock-а того же типа.

Другая часть расширений обрабатывает запросы на Mock-и, что гарантирует, что Mock будет создан и возвращен.

Разделение работы автомока на делегирование и стратегию создания свойств Mock-а также означает, что мы можем напрямую запросить Mock, если мы хотим этого. Более того, мы можем использовать встроенную поддержку метода Freeze для замораживания Mock-а, а также автоматически замораживать и экземпляр автомока (потому что делегиорвание запросит Mock, который окажется замороженным).

Возвращаясь к первому примеру «замороженной» пиццы, мы можем теперь переписать его так:

[Fact]
public void AddWillPipeMapCorrectly()
{
    // Fixture setup
    var fixture = new Fixture()
        .Customize(new AutoMoqCustomization());
    
    var basket = fixture.Freeze<Basket>();
    var mapMock = fixture.Freeze<Mock<IPizzaMap>>();
    
    var pizza = fixture.CreateAnonymous<PizzaPresenter>();
    
    var sut = fixture.CreateAnonymous<BasketPresenter>();
    // Exercise system
    sut.Add(pizza);
    // Verify outcome
    mapMock.Verify(m => m.Pipe(pizza, basket.Add));
    // Teardown
    ...
}

Обратите внимание, что мы можем просто заморозить Mock, который также автоматически заморозит экземпляр IPizzaMap. Когда мы позже создаем SUT, запросив анонимный BasketPresenter, IPizzaMap уже “вморожен” в Fixture, поэтому правильный экземпляр будет внедрён в SUT.


comments powered by Disqus