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

#c# #moq #autofixture #automoq

#c# #moq #автофиксация #automoq

Вопрос:

В моих тестах используются Moq и AutoFixture, и часто они очень подробные, потому что в них есть много вызовов mock Setup() для настройки mocks на возврат значений, созданных AutoFixture. Чтобы упростить чтение и обслуживание тестов, я пытаюсь использовать AutoMoqCustomization с функцией ConfigureMembers, чтобы избежать ненужных вызовов Setup().

В основном это работает так, как ожидалось, однако у меня есть некоторые интерфейсы с универсальными функциями (в основном AutoMapper), которые AutoMoqCustomization, похоже, не обрабатывает. Вместо возврата экземпляра типа из AutoFixture я получаю издевательский экземпляр.

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

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

Я ожидаю, что вызов sut.Map<object>() будет работать так же, как вызов sut.Map() , возвращая экземпляр object , замороженный в устройстве. Вместо этого в переменной retB я вижу экземпляр ObjectProxy .

Включение в пример строки с комментариями, которая задает возвращаемое значение для Map<object>() , приведет к прохождению теста, но я бы предпочел опустить этот вызов так же, как я могу опустить вызов Setup() для Map() .

Предполагается, что универсальные функции настраиваются автоматически? Я неправильно это настраиваю?

 using AutoFixture;
using AutoFixture.AutoMoq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace UnitTestProject1
{
    public interface IMapper
    {
        object Map();
        object Map<T>();
    }

    [TestClass]
    public class Tests
    {
        [TestMethod]
        public void Test()
        {
            var f = new Fixture().Customize(new AutoMoqCustomization { ConfigureMembers = true });
            var model = f.Freeze<object>();
            var sut = f.Create<IMapper>();

            //Mock.Get(sut).Setup(x => x.Map<object>()).ReturnsUsingFixture(f);

            var retA = sut.Map();
            var retB = sut.Map<object>();

            Assert.AreEqual(model, retA);
            Assert.AreEqual(model, retB);        }
    }
}

  

Ответ №1:

Действительно, универсальные методы в настоящее время не поддерживаются настройкой AutoMoq в autofixture из-за ограничения способа ее написания, но есть проблема / PR, которая позволила бы ее интегрировать: https://github.com/AutoFixture/AutoFixture/issues/1139

Насколько я могу судить, это просто еще не объединено, потому что это привело бы к более высокой версии зависимости от Moq. В нем используется относительно недавно введенное DefaultValueProvider свойство Moq для делегирования всех обязанностей по «значению по умолчанию» автоматической фиксации вместо того, чтобы Moq рекурсивно вводил издевательские объекты. Звучит именно так, как вы хотите.

Из проблемы, вот пример того, как это выглядело бы, если бы вы вводили настройку, аналогичную той, которую вводит запрос на извлечение:

 var fixture = new Fixture();
fixture.Customize<string>(x => x.FromSeed(y => "asf"));
var mock = new Mock<IInterfaceWithGenericMethod>
{
    DefaultValueProvider = new AutoFixtureValueProvider(fixture)
};

Assert.Equal("asf", mock.Object.GenericMethod<string>());
  

Комментарии:

1. Отличное спасибо! Я просто добавлю вызовы Setup () на данный момент и с нетерпением жду обновлений.