如何添加使用 Autofixture 创建的 Mock 的特定实现?
How to add a specific implementation of a Mock created with Autofixture?
我正在为 class(我们称之为 Sut
)编写测试,其中有一些通过构造函数注入的依赖项。为此 class 我必须使用参数最多的构造函数,因此我使用了 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 的特定测试添加此实现?
使用您创建的 IFixture,您可以针对特定接口调用 .Register 并提供随后使用该接口时要使用的对象。
例如
_fixture = new Fixture().Customize(new AutoMoqCustomization());
_fixture.Register<Interface3>(() => yourConcreteImplementation);
您还可以使用模拟,这样您就可以在夹具上使用 .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
enumeration的成员。
如果您需要将其作为 one-off 测试来执行,那么 Enrico Campidoglio 的回答就是正确的选择。
如果您需要将此作为贯穿所有单元测试的通用规则,您可以使用 TypeRelay
:
自定义 Fixture
fixture.Customizations.Add(
new TypeRelay(
typeof(IInterface3),
typeof(IInterface3TestImplementation));
这将更改 fixture
,以便在需要 IInterface3
时,将创建并使用 IInterface3TestImplementation
的实例。
我正在为 class(我们称之为 Sut
)编写测试,其中有一些通过构造函数注入的依赖项。为此 class 我必须使用参数最多的构造函数,因此我使用了 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 的特定测试添加此实现?
使用您创建的 IFixture,您可以针对特定接口调用 .Register 并提供随后使用该接口时要使用的对象。
例如
_fixture = new Fixture().Customize(new AutoMoqCustomization());
_fixture.Register<Interface3>(() => yourConcreteImplementation);
您还可以使用模拟,这样您就可以在夹具上使用 .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
enumeration的成员。
如果您需要将其作为 one-off 测试来执行,那么 Enrico Campidoglio 的回答就是正确的选择。
如果您需要将此作为贯穿所有单元测试的通用规则,您可以使用 TypeRelay
:
Fixture
fixture.Customizations.Add(
new TypeRelay(
typeof(IInterface3),
typeof(IInterface3TestImplementation));
这将更改 fixture
,以便在需要 IInterface3
时,将创建并使用 IInterface3TestImplementation
的实例。