3

I have an unit-test written with FakeItEasy v2.2.0.

The test tests that a method, let call it MethodA call to MethodB.

The simple class:

public class Foo
{
    public virtual void MethodA()
    {
        MethodB();
    }

    public virtual void MethodB() { }
}

The simple test:

var foo_fake = A.Fake<Foo>(options => options.CallsBaseMethods());

foo_fake.MethodA();

A.CallTo(() => foo_fake.MethodA()).MustHaveHappened()
    .Then(A.CallTo(() => foo_fake.MethodB()).MustHaveHappened());

With FakeItEasy 2.2.0, the code passed.

But when we upgrade to 5.1.0, the code throw exception that says:

The calls were found but not in the correct order among the calls

When we say the method is called? At the start of execution, or at the end?

Or, what is the right way to test this case?

baruchiro
  • 5,088
  • 5
  • 44
  • 66

2 Answers2

2

The call to MethodB happens and completes before MethodA has completed. Which explains the order message. It (FakeItEasy) records called at the end of the invocation of the member.

To prove my point, the following passes when tested

A.CallTo(() => foo_fake.MethodB()).MustHaveHappened() //<-- Note MethodB checked first
    .Then(A.CallTo(() => foo_fake.MethodA()).MustHaveHappened());

I suggest the following

//Arrange
var foo_fake = A.Fake<Foo>(options => options.CallsBaseMethods());
Action<Foo> subject = foo => foo.MethodA();

//Act
subject(foo_fake);

//Assert
A.CallTo(() => foo_fake.MethodA()).MustHaveHappened();
A.CallTo(() => foo_fake.MethodB()).MustHaveHappened();
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Sorry, That's not the answer.You're right it's depcrated, but the question still remains. Where is your reference to `then`? – baruchiro Apr 14 '19 at 16:08
  • @Baruch yours is s special case as the methods being assert call each other. – Nkosi Apr 14 '19 at 16:10
  • Yes, of course it will work, I've already checked it. But do you say that the `MethodA` that call to `MethodB`, invoked **after** `MethodB`? It is not right to say such a thing, so the test will not be clear. – baruchiro Apr 14 '19 at 16:13
  • 1
    I am just reporting what the code was written to do. I agree that will not be clear. – Nkosi Apr 14 '19 at 16:14
  • @Baruch you could consider raising that as an issue with the dev on Github – Nkosi Apr 14 '19 at 16:16
2

Update: this was a bug, and has been fixed. As of FakeItEasy 5.1.1, the behaviour is restored to what it was in 2.2.0


We record that a call was made after the call is finished, so in your case, the order would be

  • execute methodA
  • execute methodB
  • record that methodB happened
  • record that methodA happened

However, in 3.4.2, we released the fix to Setting ref argument values masks incoming argument values used to verify calls. This moved the point at which we record the call's "sequence number" from within the CastleInvocationCallAdapter to the FakeManager. The former would have recorded methodA's invocation before the call to methodB.

It's a shame this breaks your use case. I consider the new behaviour to be a bug, and created issue #1583 - Calls are recorded after applying the best rule, not when received on GitHub.

Personally, though, I'd look at the test (which I assume is more complicated than you presented here). I'd take @Nikosi's advice and not check the order of the calls. Knowing that they were both called (or even just that methodB was called) might be enough.

Blair Conrad
  • 233,004
  • 25
  • 132
  • 111
  • 2
    @Baruch, you say you're making an issue over on GitHub. I've been refreshing the list and don't see it yet. If you've changed your mind, I will create one to explore the effects of moving the "record the call" call to _before_ we actually execute the configured behaviour. (I just tried it out and all our existing tests pass, but maybe there's a reason not to make the change.) – Blair Conrad Apr 14 '19 at 16:31
  • You could consider making it configurable depending on the tastes of the user. the default could be after completion with the option to change it to before. But then again it might end up becoming scope creep. – Nkosi Apr 14 '19 at 16:41
  • What do you think about `MustHaveStarted`. A call to MethodA MustHaveStarted then a call to MethodB... – Nkosi Apr 14 '19 at 16:43
  • @BlairConrad I can't open an issue for now, I will thank you if you do this! – baruchiro Apr 14 '19 at 17:07
  • 1
    I've created issue [1583](https://github.com/FakeItEasy/FakeItEasy/issues/1583). @Nikosi, I copied your comments there, since SO comments aren't well-suited to involved discussion. Let's continue there, if you're able. – Blair Conrad Apr 14 '19 at 17:30
  • @BlairConrad acknowledged. – Nkosi Apr 14 '19 at 18:35