问题描述
我的测试使用Moq和AutoFixture,并且它们通常很冗长,因为它们有许多模拟Setup()调用来配置模拟以返回由AutoFixture创建的值。为了使测试更易于阅读和维护,我尝试将automoqCustomization与ConfigureMembers功能配合使用,以避免不必要的Setup()调用。
通常这可以按预期工作,但是我有一些具有通用功能的接口(主要是AutoMapper),而automoqCustomization似乎无法处理。我没有从AutoFixture返回类型的实例,而是收到了模拟的实例。
我可以通过包含泛型函数的Setup()调用来实现所需的行为,但是我的目标是删除尽可能多的此类Setup调用。
我已经建立了下面的示例来重现该问题(在实践中,我正在使用AutoFixture通过另一个对象的构造函数注入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); }
}
}
解决方法
实际上,由于固定方式的编写上的限制,Autofix中的AutoMoq定制当前不支持通用方法,但是有一个问题/ PR将其集成: https://github.com/AutoFixture/AutoFixture/issues/1139
据我所知,它尚未合并,因为它将引入更高的Moq依赖版本。它利用Moq的最近引入的DefaultValueProvider
属性将所有“默认值”职责委派给AutoFixture,而不是让Moq递归地引入模拟对象。听起来确实就是您想要的。
从问题开始,下面是一个示例,说明您要引入类似于the pull request的自定义设置的自定义设置:
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>());