为什么AutoFixture的AutoMoqData不会创建模拟对象?

时间:2017-01-29 10:54:37

标签: unit-testing nunit moq autofixture

我正在编写(NUnit)单元测试,其目标是MyService类型的组件。例如:

public class MyService : IMyService
{
    private readonly IMyRepo _myRepo;

    public MyService (IMyRepo myRepo)
    {
        _myRepo = myRepo;
    }

    public MyService ()
    {
        _myRepo = new MyRepo();
    }
    ...
}

我正在尝试将AutoFixture用作生成我的测试目标的factory。我也试图让它(AutoFixture)使用模拟依赖项填充我的目标(使用Moq)。

我尝试这样做:

[Test, AutoMoqData]
public void MyTest(MyService target)
{
    ...
}

[AutoMoqData]属性(基于@ploeh's blog post)使用AutoFixture的[AutoData]功能扩展了AutoFixture的AutoMoqCustomization属性:

public class AutoMoqDataAttribute : AutoDataAttribute
{
    public AutoMoqDataAttribute()
        : base(new Fixture()
            .Customize(new AutoMoqCustomization()))
    {
    }
}

当我基于上面的内容运行单元测试时,我希望得到一个MyService的真实实例,其中包含Mock<IMyRepo>依赖项。 相反,我得到了MyRepo的具体实例。

似乎AutoMoqCustomization选择调用最简单的构造函数 - 没有参数的构造函数。 如何配置AutoMoqCustomization忽略它而改为实例化第二个构造函数

PS - 以下是正在使用的相关nuget包的列表:
<package id="AutoFixture" version="3.50.2" targetFramework="net452" /> <package id="AutoFixture.AutoMoq" version="3.50.2" targetFramework="net452" /> <package id="AutoFixture.NUnit3" version="3.50.2" targetFramework="net452" /> <package id="Moq" version="4.5.29" targetFramework="net452" /> <package id="NUnit" version="3.5.0" targetFramework="net452" />

1 个答案:

答案 0 :(得分:2)

您可以尝试define a greedy constructor selection algorithm for AutoFixture,但实际上,最佳解决方案是删除无参数构造函数:

public class MyService : IMyService
{
    private readonly IMyRepo _myRepo;

    public MyService (IMyRepo myRepo)
    {
        _myRepo = myRepo;
    }
}

拥有无参数构造函数是一种称为 Bastard Injection 的代码气味。在大多数情况下,没有充分的理由。

在我看来,最好的选择是应用GOOS听取测试的原则。当测试变得难以编写时,是时候重新考虑被测系统(SUT)的设计了。 AutoFixture倾向于放大这种效果。这就是这里发生的事情。