在同一对象上调用了两次,当MustHaveHappened失败(MustHaveHappened f

2019-09-23 23:51发布

给出下面的类被测(和相关联的DTO类和接口):

public class Foo
{
    private readonly IBar _bar;

    public Foo(IBar bar) { _bar = bar; }

    public void DoStuff()
    {
        var dto = new DTO();

        dto.Num = 1;
        _bar.Test(dto);

        dto.Num = 2;
        _bar.Test(dto);
    }
}

public class DTO { public int Num { get; set; } }

public interface IBar { void Test(DTO dto); }

并且这种测试方法(其尝试验证IBar.Test()被调用两次:一次货号= 1,并用货号= 2一次):

public void TestMethod1()
{
    var bar = A.Fake<IBar>();
    var foo = new Foo(bar);
    foo.DoStuff();

    A.CallTo(() => bar.Test(A<DTO>.That.Matches(x => x.Num == 1))).MustHaveHappened();
    A.CallTo(() => bar.Test(A<DTO>.That.Matches(x => x.Num == 2))).MustHaveHappened();
}

第一个“MustHaveHappened”呼叫失败。 我发现,这是因为双方使用的DTO调用IBar.Test()是相同的实例。 如果我改变代码来调用IBar.Test()有两种不同的DTO的它按预期工作。

我的问题是:这是FakeItEasy的错误还是我做错了什么?

Answer 1:

这是正确的行为,而不是一个错误。 FakeItEasy记录带参数调用,但它在通话过程中不存储参数的内部状态-它只是存储参数本身的参考/值。 最后,在您的验证阶段, DTO对象的当前状态是一个与Num等于2,这就是FakeItEasy将验证反对。

我不知道是否有出于对此类案件箱支持,但是你可以很容易地实施这种解决方法(不创建第二DTO对象):

var bar = A.Fake<IBar>();
var foo = new Foo(bar);
var expectedNumValues = new [] { 1, 2 };
var actualNumValues = new List<int>();
// Whenever a call to IBar.Test is made, store DTO.Num in list
A.CallTo(() => bar.Test(A<DTO>.Ignored)).Invokes(
    fakeCall =>
    {
        var dto = (DTO) fakeCall.Arguments[0];
        actualNumValues.Add(dto.Num);
    }
);

foo.DoStuff();

// this verifies that both collections contain same elements at same positions
CollectionAssert.AreEqual(expectedNumValues, actualNumValues);


文章来源: MustHaveHappened fails when called twice on the same object