如何添加使用Autofixture创建的Mock的特定实现

本文关键字:创建 Mock 实现 Autofixture 何添加 添加 | 更新日期: 2023-09-27 18:30:13

我正在为类(让我们称之为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的特定测试添加这个实现?

如何添加使用Autofixture创建的Mock的特定实现

如果你需要一次性测试,那么Enrico Campidoglio的答案就是你的选择。

如果您在所有单元测试中都需要这一点,那么您可以使用TypeRelay:自定义Fixture

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

这将更改fixture,以便无论何时需要IInterface3,都将创建并使用IInterface3TestImplementation的实例。

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

例如

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

你也可以使用mocking,这样就可以在fixture上使用.Freeze,这样你就可以对接口设置一些预期的调用,而不需要一个完全具体的实例。您可以让AutoFixture为您创建一个默认实现,并应用您配置的设置。

例如

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

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

[Theory, AutoMoqDataAttributeGreedy]
public void SomeTest(
    [Frozen]Mock<IInterface1> mock1,
    [Frozen]Mock<IInterface2> mock2,
    [Frozen(Matching.ImplementedInterfaces)]IInterface3TestImplementation impl3,
    Sut sut)
{
}

在这种情况下,AutoFixture将创建IInterface3TestImplementation的实例,并在每次遇到该类型实现的接口时使用它。

这意味着,如果Sut的构造函数有一个类型为IInterface3的参数,AutoFixture将向它传递与分配给impl3参数的实例相同的实例,您可以在测试中使用该实例。

顺便说一句,除了通过接口之外,还有其他方式将冻结的实例与类型和成员进行匹配。如果您想了解更多信息,请查看Matching枚举的成员。