自动 return 来自模拟泛型函数的夹具值?

Automatically return fixture values from mocked generic functions?

我的测试使用 Moq 和 AutoFixture,它们通常非常冗长,因为它们有许多模拟 Setup() 调用来将模拟配置为由 AutoFixture 创建的 return 值。为了使测试更易于阅读和维护,我尝试将 AutoMoqCustomization 与 ConfigureMembers 功能结合使用,以避免不必要的 Setup() 调用。

大多数情况下这是按预期工作的,但是我有一些接口具有 AutoMoqCustomization 似乎无法处理的通用函数(主要是 AutoMapper)。我没有从 AutoFixture returning 一个类型的实例,而是收到一个模拟实例。

我可以通过包含对通用函数的 Setup() 调用来实现我想要的行为,但我的目标是尽可能多地删除这些 Setup 调用。

我已经设置了下面的示例来重现问题(实际上我使用 AutoFixture 通过另一个对象的构造函数注入 IMapper 实例,并且该对象调用了 IMapper 接口,但事实并非如此有必要查看有问题的行为)。

我希望对 sut.Map<object>() 的调用能够像对 sut.Map() 的调用一样工作,return 冻结固定装置中的 object 实例。相反,在变量 retB 中,我看到了 ObjectProxy.

的一个实例

在为 Map<object>() 设置 return 值的示例中包含注释行将导致测试通过,但我更愿意以与我相同的方式省略此调用省略 Map().

的 Setup() 调用

是否应该自动配置通用函数?我设置不正确吗?

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);        }
    }
}

事实上,autofixture 中的 AutoMoq 自定义目前不支持通用方法,因为它的编写方式受到限制,但是有一个 issue/PR 可以集成它: https://github.com/AutoFixture/AutoFixture/issues/1139

据我所知,它还没有合并,因为它会引入更高的 Moq 依赖版本。它利用 Moq 引入的 relatively-recently DefaultValueProvider 属性 将所有 'default value' 职责委托给 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>());