如何添加使用Autofixture创建的模拟的特定实现?

时间:2016-01-14 11:23:39

标签: c# tdd xunit autofixture

我正在编写类的测试(让我们称之为Sut),它通过构造函数注入一些依赖项。对于这个类,我必须使用具有最多参数的构造函数,因此我使用了AutoMoqDataAttributeGreedy实现:

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

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

我的sut的构造函数看起来像这样:

public class Sut(IInerface1 interface1, IInterface2 interface2, IInterface3 interface3)
{
    Interface1 = interface1;
    Interface2 = interface2;
    Interface3 = interface3;
}

一个示例测试如下:

[Theory, AutoMoqDataAttributeGreedy]
public void SomeTest([Frozen]Mock<IInterface1> mock1 ,
                      Mock<IInterface2> mock2, 
                      Sut sut, 
                      SomOtherdata data)
{
    // mock1 and mock2 Setup omitted

    // I want to avoid following line
    sut.AddSpeficicInterfaceImplementation(new IInterface3TestImplementation());

    sut.MethodIWantToTest();

    //Assert omitted 
}

问题是我需要IInterface3的特定实现进行测试,我想避免仅为我的单元测试添加一个方法到我的SUT(Interface3TestImplementation),我也想避免重复代码,因为我必须在每个测试中添加此实例。

是否有一种漂亮而巧妙的方法可以为我的所有测试/使用Autofixture进行特定测试添加此实现?

3 个答案:

答案 0 :(得分:4)

您可以让AutoFixture创建具体类型的实例,并告诉它每次必须为其任何实现的接口提供值时使用该实例。这是一个例子:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="number" id="numRepeat" value="0"/>

<div id="model-div">
    <div class="repeat-me">REPEAT</div>
</div>

<div id="result-div"></div>

在这种情况下,AutoFixture将创建[Theory, AutoMoqDataAttributeGreedy] public void SomeTest( [Frozen]Mock<IInterface1> mock1, [Frozen]Mock<IInterface2> mock2, [Frozen(Matching.ImplementedInterfaces)]IInterface3TestImplementation impl3, Sut sut) { } 的实例,并在每次遇到由该类型实现的接口时使用它。

这意味着如果IInterface3TestImplementation的构造函数具有Sut类型的参数,则AutoFixture将向其传递被分配的相同实例IInterface3参数,您可以在测试中使用该参数。

除此之外,还有将冻结实例与除了接口之外的类型和成员匹配的其他方式。如果您想了解更多信息,请查看Updated fiddle的成员。

答案 1 :(得分:4)

如果您需要将此作为一次性测试,那么Enrico Campidoglio的答案就是您的选择。

如果您在所有单元测试中都需要将此作为一般规则,则可以使用Fixture自定义TypeRelay

fixture.Customizations.Add(
    new TypeRelay(
        typeof(IInterface3),
        typeof(IInterface3TestImplementation));

这将更改fixture,这样,只要需要IInterface3,就会创建并使用IInterface3TestImplementation的实例。

答案 2 :(得分:2)

使用您创建的IFixture,可以针对特定接口调用.Register,并在随后使用该接口时提供要使用的对象。

e.g。

_fixture = new Fixture().Customize(new AutoMoqCustomization());
_fixture.Register<Interface3>(() => yourConcreteImplementation);

您还可以使用模拟,然后允许您在灯具上使用.Freeze,这样您就可以设置一些针对接口的预期调用,并且不需要完全具体的实例。您可以让AutoFixture为您创建默认实现并应用您配置的设置。

e.g。

var mockedInterface = _fixture.Freeze<Mock<Interface3>>();
mockedInterface
    .Setup(x => x.PropertyOnInterface)
    .Returns("some value");