首先,我将在 OP 的 GitHub 存储库TypesWithoutPublicCtrs
中定义的假设下回答这个问题:
public class TypesWithoutPublicCtrs
{
private readonly IMyInterface _mi;
public TypesWithoutPublicCtrs(IMyInterface mi)
{
_mi = mi;
}
}
我明确指出这一点的原因是因为这个名字是一个红鲱鱼:它确实有一个公共构造函数;它只是没有默认构造函数。
无论如何,AutoFixture 很容易处理默认构造函数的缺失。这里的问题不是TypesWithoutPublicCtrs
类本身,而是IMyInterface
接口。接口是有问题的,因为它们根本无法初始化。
因此,您需要以某种方式将接口映射到具体类。有多种方法可以做到这一点。
一次性解决方案
偶尔,我会使用这种一次性解决方案,尽管我觉得它很难看。但是,它很容易,不需要很多复杂的设置。
[Theory, AutoData]
public void TestSomething(
[Frozen(As = typeof(IMyInterface))]FakeMyInterface dummy,
TypesWithoutPublicCtrs sut)
{
// use sut here, and ignore dummy
}
这不是特别好,因为它依赖于属性的副作用[Frozen]
,但它可以作为一个独立的一次性解决方案。
习俗
但是,我更喜欢对其进行约定,以便相同的约定适用于测试套件中的所有测试。使用这种约定的测试可能如下所示:
[Theory, MyTestConventions]
public void TestSomething(TypesWithoutPublicCtrs sut)
{
// use sut here; it'll automatically have had FakeMyInterface injected
}
该[MyTestConventions]
属性可能如下所示:
public class MyTestConventionsAttribute : AutoDataAttribute
{
public MyTestConventionsAttribute() :
base(new Fixture().Customize(new MyTestConventions())
{}
}
类MyTestConventions
必须实现接口ICustomization
。您可以通过多种方式映射IMyInterface
到FakeMyInterface
; 这是一个:
public class MyTestConventions : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(
new TypeRelay(typeof(IMyInterface), typeof(FakeMyInterface)));
}
}
自动模拟
但是,您可能厌倦了必须创建和维护所有这些 Fakes,因此您也可以将 AutoFixture 变成Auto-Mocking Container。有多种选择可以做到这一点,利用 Moq、NSubstitute、FakeItEasy和Rhino Mocks 。