Автоматическая настройка AutoFixture возвращает тип настройки Task ‹IEnumerable‹ ››

Я использую AutoFixture с AutoMoqCustomization в своих тестах.

У меня есть сервис, который зависит от тестируемой системы:

ISomeService
{
    Task<IEnumerable<int>> Get();
}

Я называю это внутри тестируемой системы:

var collection = await _someService.Get(); // collection is empty

Меня не волнует, что внутри коллекции, но мне нужно, чтобы коллекция не была пустой. Я так делаю:

_fixture.Freeze<Mock<ISomeService>>()
            .Setup(service => service.Get())
            .Returns(Task.FromResult(_fixture.CreateMany<int>()));

Похоже, это нужно делать с настройкой. Я создал и зарегистрировал один:

public class TaskCollectionCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customizations.Add(
            new FilteringSpecimenBuilder(
                new TaskCollectionBuilder(),
                new GenericTypeSpecification(typeof(Task<>))));
    }

    private class TaskCollectionBuilder : ISpecimenBuilder
    {
        public object Create(object request, ISpecimenContext context)
        {
            // never enters here
        }
    }
}

Проблема в том, что метод Create никогда не вводится. Есть идеи или готовые решения?

ИЗМЕНИТЬ

Добавление источника GenericTypeSpecification

public class GenericTypeSpecification : IRequestSpecification
{
    private readonly Type _type;

    public GenericTypeSpecification(Type type)
    {
        _type = type;
    }

    public bool IsSatisfiedBy(object request)
    {
        var requestedType = request as Type;

        return requestedType != null &&
               requestedType.IsGenericType &&
               requestedType.GetGenericTypeDefinition() == _type;
    }
}

person Andrzej Gis    schedule 05.03.2015    source источник
comment
Что такое GenericTypeSpecification?   -  person Mark Seemann    schedule 06.03.2015
comment
@MarkSeemann Извините, я думал, что это часть библиотеки, но оказалось, что ее создал другой член команды. См. Редактирование, пожалуйста.   -  person Andrzej Gis    schedule 06.03.2015
comment
Не вижу никаких изменений ...   -  person Mark Seemann    schedule 06.03.2015
comment
@MarkSeemann Забыл нажать кнопку "Сохранить изменения".   -  person Andrzej Gis    schedule 06.03.2015


Ответы (1)


AutoFixture уже "из коробки" поддерживает Задачи, о чем свидетельствует этот Тест характеристик:

[Fact]
public void AutoFixtureAlreadySupportsTasks()
{
    var fixture = new Fixture();
    var t = fixture.Create<Task<IEnumerable<int>>>();
    Assert.NotEmpty(t.Result);
}

Таким образом, все, что вам нужно для настройки Test Double вашего Сервиса, выглядит примерно так:

[Fact]
public void ConfigureMock()
{
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    fixture.Freeze<Mock<ISomeService>>()
        .Setup(s => s.Get())
        .Returns(fixture.Create<Task<IEnumerable<int>>>());

    var svc = fixture.Create<ISomeService>();

    Assert.NotEmpty(svc.Get().Result);
}

Если вы думаете, что это слишком много работы, вы также можете попросить AutoConfiguredMoqCustomization сделать это вместо вас, например:

[Fact]
public void SimplestCustomization()
{
    var fixture = 
        new Fixture().Customize(new AutoConfiguredMoqCustomization());
    var svc = fixture.Create<ISomeService>();
    Assert.NotEmpty(svc.Get().Result);
}

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

person Mark Seemann    schedule 06.03.2015
comment
Спасибо. AutoConfiguredMoqCustomization действительно сработал. С другой стороны, если зарегистрированы как AutoConfiguredMoqCustomization, так и AutoMoqCustomization настройки, он не настраивает макеты автоматически. Не уверен, ошибка это или дизайн. :) - person Andrzej Gis; 06.03.2015
comment
Это может быть по дизайну, но я не могу сказать больше, так как не незнаю подробности. - person Mark Seemann; 06.03.2015
comment
@gisek Будет запущена только одна из двух настроек, это зависит от того, какую из них вы примените в первую очередь. Поскольку AutoConfiguredMoqCustomization является расширенным набором AutoMoqCustomization, нет необходимости использовать оба одновременно. В качестве примечания, вы также можете сделать .ReturnsUsingFixture(fixture) вместо .Returns(fixture.Create<Task<IEnumerable<int>>>()) - person dcastro; 11.03.2015
comment
@dcastro Спасибо! Я не знал о методе ReturnsUsingFixture. Смотрится очень полезно. - person Andrzej Gis; 12.03.2015