Почему AutoFixture AutoMoqData не создает фиктивные объекты?

Я пишу (NUnit) модульные тесты, нацеленные на компонент типа MyService. Пример:

public class MyService : IMyService
{
    private readonly IMyRepo _myRepo;

    public MyService (IMyRepo myRepo)
    {
        _myRepo = myRepo;
    }

    public MyService ()
    {
        _myRepo = new MyRepo();
    }
    ...
}

Я пытаюсь использовать AutoFixture в качестве фабрика, которая сгенерирует мою тестовую цель. Я также пытаюсь заставить его (AutoFixture) заполнить мою цель фиктивными зависимостями (используя Moq).

Вот моя попытка сделать это:

[Test, AutoMoqData]
public void MyTest(MyService target)
{
    ...
}

Атрибут [AutoMoqData] (на основе сообщения в блоге @ploeh) расширяет атрибут [AutoData] AutoFixture. с функцией AutoFixture AutoMoqCustomization:

public class AutoMoqDataAttribute : AutoDataAttribute
{
    public AutoMoqDataAttribute()
        : base(new Fixture()
            .Customize(new AutoMoqCustomization()))
    {
    }
}

Когда я запускаю модульные тесты на основе вышеизложенного, я хотел бы получить реальный экземпляр MyService с зависимостью Mock<IMyRepo> внутри него. Вместо этого я получаю конкретный экземпляр MyRepo.

Кажется, что AutoMoqCustomization предпочитает вызывать самый простой конструктор — тот, у которого нет аргументов. Как настроить AutoMoqCustomization, чтобы он игнорировался и вместо этого создавался второй конструктор?

PS. Вот список соответствующих используемых пакетов nuget:
<package id="AutoFixture" version="3.50.2" targetFramework="net452" /> <package id="AutoFixture.AutoMoq" version="3.50.2" targetFramework="net452" /> <package id="AutoFixture.NUnit3" version="3.50.2" targetFramework="net452" /> <package id="Moq" version="4.5.29" targetFramework="net452" /> <package id="NUnit" version="3.5.0" targetFramework="net452" />


person urig    schedule 29.01.2017    source источник
comment
Перечислите зависимости вашего пакета NuGet.   -  person Mark Seemann    schedule 29.01.2017
comment
Пожалуйста, опубликуйте шаги для воспроизведения. Как вы наблюдаете, что зависимость не такая, какой вы хотели бы ее видеть?   -  person Mark Seemann    schedule 29.01.2017
comment
Спасибо @MarkSeemann. Только что попробовал минимальное воспроизведение в новом проекте, и теперь оно работает. Скоро обновится.   -  person urig    schedule 29.01.2017
comment
Ой. Я обнаружил, что MyService имеет пустой конструктор с _myRepo = new MyRepo() в нем. Теперь перефразирую свой вопрос в связи с этим.   -  person urig    schedule 29.01.2017


Ответы (1)


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

public class MyService : IMyService
{
    private readonly IMyRepo _myRepo;

    public MyService (IMyRepo myRepo)
    {
        _myRepo = myRepo;
    }
}

Наличие конструктора без параметров — это запах кода, который называется Bastard Injection. В большинстве случаев для этого нет веских причин.

На мой взгляд, лучший вариант — применить принцип GOOS для прослушивания ваших тестов. Когда тест становится трудно писать, пришло время пересмотреть дизайн тестируемой системы (SUT). AutoFixture имеет тенденцию усиливать этот эффект. Вот что здесь происходит.

person Mark Seemann    schedule 29.01.2017
comment
Большое спасибо за супер-быстрое решение. Действительно пустой ctor - это запах кода: [Obsolete("Please don't use this ctor. Only in use for old static classes being phased out.", false)]. Усердно работаем над его прояснением :) ` - person urig; 29.01.2017