MustHaveHappened fails when called twice on the same object

天涯浪子 提交于 2019-12-08 01:52:59

问题


Given the following class under test (and associated DTO class and interface):

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); }

And this test method (which attempts to verify that IBar.Test() gets called twice: once with Num = 1 and once with Num = 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();
}

The first 'MustHaveHappened' call fails. I have discovered that it is because the DTO used by both calls to IBar.Test() is the same instance. If I change the code to call IBar.Test() with two different DTO's it works as expected.

My question is: is this a bug in FakeItEasy or am I doing something wrong?


回答1:


This is correct behavior, not a bug. FakeItEasy records calls with arguments, but it doesn't store arguments' internal state during the call - it simply stores reference/value of the argument itself. At the end, during your verification phase, DTO object's current state is the one with Num equal to 2, and that's what FakeItEasy will verify against.

I'm not sure whether there's out of box support for such cases, but you can easily implement workaround for this (without creating second DTO object):

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);


来源:https://stackoverflow.com/questions/12846484/musthavehappened-fails-when-called-twice-on-the-same-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!