Autofixture макет интерфейса для возврата случайных результатов в целях тестирования

Эта проблема

У меня есть довольно большое приложение, которое использует кучу других сервисов. Для сценариев тестирования я не хочу, чтобы мои модульные тесты опирались на сторонние системы, поэтому я хочу заменить службы поддельными, поддельными или какими-либо другими.

Я уже сделал большую часть тяжелого труда, и заменил конкретные услуги IService, Конкретная служба подключена к DI-фреймворку

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

Код

Интерфейс примера сервиса:

public interface ISimpleService
{
    int Fizz(int input);

    string Buzz(string input);
}

Интерфейс примера сервисной фабрики:

public interface ISimpleServiceFactory
{
    ISimpleService Create();
}

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

public static void Main(string[] args)
{
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    var service = fixture.Create<ISimpleService>();

    var fizzResult = service.Fizz(42);
    var buzzResult = service.Buzz("I'd like something random...");
}

Это показывает, чего я в основном хочу. Я просто хочу, чтобы autofixture создала для меня динамический прокси-объект с методами, которые возвращают что-то случайное типа, указанного в интерфейсе...

Обратите внимание, что я использовал AutoMoq здесь, потому что по умолчанию Fixture не хочет создавать объекты из интерфейсов, но я пробовал и другие фреймворки: FakeItEasy, AutoRhinoMock

Временное решение

Реализация такого рода работ осуществляется путем ручной настройки всего

public static void Main(string[] args)
{
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    var serviceMock = fixture.Create<Mock<ISimpleService>>();

    // These two lines below cause the magic now
   serviceMock.Setup(x => x.Fizz(It.IsAny<int>())).Returns(fixture.Create<int>());
   serviceMock.Setup(x => x.Buzz(It.IsAny<string>())).Returns(fixture.Create<string>());

    var service = serviceMock.Object;
    var fizzResult = service.Fizz(42);
    var buzzResult = service.Buzz("I'd like something random...");
}

Это дает мне желаемый результат: fizzResult со случайным int, buzzResult со случайной строкой (по умолчанию guid). Однако, это только небольшой пример, мои фактические ссылки на службы намного больше, с до 100 методов... (это внешние мыльные сервисы и т. д., ничего не поделаешь) Я не хочу настраивать все вручную, если есть универсальное решение, это было бы здорово...

Реализация для фабрик такого рода, вручную настраивая все

Итак, как вы могли заметить, я также опубликовал ISimpleServiceFactory интерфейс. Это напоминает реальную ситуацию, так как фактический конкретный ISimpleService требует кучу настроек. Итак, если бы мы использовали вид рабочего решения, мы пришли бы к этому:

public static void Main(string[] args)
{
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    var serviceFactoryMock = fixture.Create<Mock<ISimpleServiceFactory>>();

    var serviceMockDelegate = new Func<ISimpleService>(() =>
        {
            var serviceMock = fixture.Create<Mock<ISimpleService>>();
            serviceMock.Setup(x => x.Fizz(It.IsAny<int>())).Returns(fixture.Create<int>());
            serviceMock.Setup(x => x.Buzz(It.IsAny<string>())).Returns(fixture.Create<string>());

            return serviceMock.Object;
        });

    serviceFactoryMock.Setup(x => x.Create()).Returns(serviceMockDelegate);
    var service = serviceFactoryMock.Object.Create();

    var fizzResult = service.Fizz(42);
    var buzzResult = service.Buzz("I'd like something random...");
}

Кажется, это немного запутанно, и это довольно маленький интерфейс. Фактические услуги имеют много уровней, с сотнями методов.

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

Есть ли способ автоматически генерировать случайные объекты без всякой ручной настройки?

1 ответ

Вам не нужна фабрика, и вам не нужно настраивать каждый метод в ваших интерфейсах, если я правильно понимаю, вы просто хотите использовать Fixture для создания прокси, который возвращает случайные значения для каждого метода, который вы вызываете на этом прокси. Вместо использования AutoMoqCustomization используйте AutoConfiguredMoqCustomization. Это все в пакете nuget под названием Fixture.AutoMoq.

class Program
{
    static void Main(string[] args)
    {
    }
}

[TestFixture]
public class program
{
    [Test]
    public void some_test()
    {
        var fixture = new Fixture();
        fixture.Customize(new AutoConfiguredMoqCustomization());

        var simpleServices = fixture.CreateMany<ISimpleService>();

        foreach (var simpleService in simpleServices)
        {
            string randomString = simpleService.Buzz("hello");
            int randomInt = simpleService.Fizz(15);
        }
    }
}

public interface ISimpleService
{
    int Fizz(int input);

    string Buzz(string input);
}
Другие вопросы по тегам