Поскольку вы поделились, что используете AutoMoqCustomization
, это объясняет поведение, которое вы видите, хотя это связано с тем, что некоторые внутренние компоненты в Moq
и AutoFixture
взаимодействуют так, как вы этого не ожидаете.
Для полноты картины приведу заглушенную версию класса и интерфейса, которые вы упомянули в своем вопросе:
public interface IMyInterface
{
Task<bool> MethodA();
Task<bool> MethodB();
}
public class Sut
{
private readonly IMyInterface dep;
public Sut(IMyInterface dep)
{
this.dep = dep;
}
public async Task<bool> Do()
{
var one = await dep.MethodA();
var two = await dep.MethodB();
return one || two;
}
}
А вот тест, который мы можем использовать для иллюстрации взаимодействия двух вариантов поведения:
[Test]
public async Task FixtureNoConfigureMembers()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization() { ConfigureMembers = false });
var mock = fixture.Freeze<Mock<IMyInterface>>();
mock.SetReturnsDefault(Task.FromResult(false));
var sut = fixture.Create<Sut>();
var result = await sut.Do();
Assert.False(result);
}
Две важные детали реализации, которые следует учитывать:
- Что делает AutoFixture, когда вы указываете
ConfigureMembers = true
в настройке. - Как Moq определяет, когда использовать значение по умолчанию, установленное
SetReturnsDefault
Поскольку оба проекта с открытым исходным кодом, достаточно просто заглянуть под обложки. Я не буду вставлять сюда каждый отдельный класс, но вы можете проверить источник Autofixture и источник Moq , если вы хотите больше деталей.
Moq's SetReturnsDefault
довольно просто Поведение:
- Если настройка совпадает, эта настройка используется. Возвращаемое значение по умолчанию игнорируется. Это важный бит.
- Если настройки не совпадают, а возвращаемое значение имеет правильный тип, возвращается значение по умолчанию.
На стороне автофиксатора ...
AutoMoqCustomization
делает так, что, когда запрашивается образец типа Mock<T>
, AutoFixture сначала создает Mock, фактически вызывая new Mock<T>()
(это немного более нюансировано, чем это, но это по существу так этот интерфейс.)
После создания макета, если ConfigureMembers
истинно, Autofixture дополнительно перечислит все виртуальные методы типа mocked и сделает эквивалент
mock.Setup(m => m.MethodName(It.IsAny<T>... for all arguments... ))
.Returns(fixture.Create<TReturn>())
Это переопределяет поведение по умолчанию AutoMoqCustomization
, которое позволяет Moq обрабатывать выбор значения по умолчанию (обычно с помощью создания своих собственных насмешек).
Вы, вероятно, можете видеть, где это возглавляется Поскольку AutoFixture создала настройки для всех виртуальных методов, это полностью переопределяет поведение SetReturnsDefault
, предоставляемое Moq.
Обратите внимание, что это поведение связано с тем, что Moq раньше не использовал метод SetReturnsDefault
- поэтому AutoFixture не может использовать DefaultValueProvider для введения образцов, которые он создает. На AutoFixture есть PR, чтобы изменить поведение для использования свойства DefaultValueProvider
, предоставленного Moq. Предположительно это восстановит способность SetReturnsDefault
переопределять поведение для определенного типа. (Хотя я не изучал PR вообще)