我想知道是否有一种方法可以在使用设置AutoData的测试用例时在调用被测系统(SUT)的构造函数之前为依赖项设置模拟。

我的SUT看起来像:

class Sut
{
    private readonly IFoo foo;
    public Sut(IFooFactory factory)
    {
        this.foo = factory.Build(1, 2);
    }

    public IFoo Foo
    {
        get
        {
            return this.foo;
        }
    }
}


因此,我正在编写的测试如下所示:

[Theory]
[AutoData]
internal void Foo_IsCorrectlySet_Test(
    [Frozen] Mock<IFooFactory> fooFactory,
    IFoo foo,
    Sut sut)
{
    fooFactory.Setup(mock => mock.Build(1, 2))
        .Returns(foo)
        .Verifiable();

    var actual = sut.Foo;

    Assert.Equal(foo, sut);
    fooFactory.Verify();
}


显然,由于Sut的构造函数在我能够设置IFooFactory之前运行,因此该测试失败。因此,我认为我可以在测试中将Sut的声明更改为Lazy<Sut>
但是构造函数仍然在实际测试代码运行之前运行,这意味着我的测试将失败。

现在,我知道我可以轻松地使用实际的Fixture对象设置此测试,并手动创建所有对象并进行设置,然后再调用创建Sut,这很好,但我想保留所有测试大致相同,因此我想知道是否存在一种方法,我仍然可以使用AutoData属性设置测试,但在完成所有设置之后才运行构造函数?

最佳答案

AutoFixture最初是作为用于测试驱动开发(TDD)的工具而构建的,而TDD只是关于反馈的。本着GOOS的精神,您应该听听测试。如果测试很难编写,则应考虑API设计。 AutoFixture倾向于放大这种反馈,在这里也可能是这种情况。

考虑Sut类的不变量。由于它具有只读的IFoo类字段,因此我将其解释为IFoo是该类的依赖项的强烈指示。

如果是这种情况,请通过构造函数而不是IFoo注入IFooFactory

public class Sut
{
    private readonly IFoo foo;
    public Sut(IFoo foo)
    {
        this.foo = foo;
    }

    public IFoo Foo
    {
        get { return this.foo; }
    }
}


您仍然可以在应用程序的Composition Root中使用IFooFactory编写它:

var sut = new Sut(aFactory.Build(1, 2));


这将使测试更易于编写。我什至无法向您展示上述重构后的测试结果,因为它是多余的,可以(并且应该)删除。

FWIW,上面提出的原始设计违反了Nikola Malovic的IoC的第4条定律constructors should do no work

关于c# - 使用AutoMoq属性模拟构造函数依赖项,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36918881/

10-08 22:26