I'm mostly using ordered expectations with GoogleMock, so all EXPECT_CALL
s were written inside the scope of a testing::InSequence
object.
Now I want to relax the ordering so I split the expectations in 2 sequences. You would say the test should pass, but no - it fails, complaining about unmet preconditions. How should I reason about this?
Edit: Reduced version of my code:
//InSequence s; // uncomment this and it works
for (int i = 1; i <= 2; ++i)
{
{
//InSequence s; // uncomment this and it doesn't work
EXPECT_CALL(mock1, produceMessage(_))
.WillOnce(DoAll(SetArgReferee<0>(val1), Return(false)))
.WillOnce(DoAll(SetArgReferee<0>(val2), Return(false)))
.WillOnce(DoAll(SetArgReferee<0>(val2), Return(false)));
EXPECT_CALL(mock2, handleEvent(A<MyType>()));
EXPECT_CALL(mock2, handleMessage(NotNull()));
}
}
So if the InSequence is nested inside the for
loop, I should have a partial order, which is a relaxed requirement, compared to the case when the InSequence is on the outside.
Error I'm getting:
Mock function called more times than expected - returning default value.
Function call: handleMessage(0xd7e708)
Returns: false
Expected: to be called once
Actual: called twice - over-saturated and active
And then, at the end of the test:
Actual function call count doesn't match EXPECT_CALL(mock2, handleMessage(NotNull()))...
Expected: to be called once
Actual: never called - unsatisfied and active
After some more progress on the GoogleMock learning curve, I'll try to answer my own question in a way that is general enough to be helpful.
Let's consider the following example of totally ordered expectations:
{
InSequence s;
EXPECT_CALL(mock1, methodA(_)); // expectation #1
EXPECT_CALL(mock2, methodX(_)); // expectation #2
EXPECT_CALL(mock1, methodA(_)); // expectation #3
EXPECT_CALL(mock2, methodY(_)); // expectation #4
}
Now, let's slice the ordering in two.
{
InSequence s;
EXPECT_CALL(mock1, methodA(_)); // expectation #1
EXPECT_CALL(mock2, methodX(_)); // expectation #2
}
{
InSequence s;
EXPECT_CALL(mock1, methodA(_)); // expectation #3
EXPECT_CALL(mock2, methodY(_)); // expectation #4
}
The intention is to allow expectations from the two sequences to "merge", i.e. to have expectation #1 as precondition for #2 and #3 for #4 but not more than that.
However, the following sequence of calls will satisfy the totally ordered expectations but not the "partially ordered" ones:
mock1.methodA(); // call #1
mock2.methodX(); // call #2
mock1.methodA(); // call #3
mock2.methodY(); // call #4
Reason: it is obvious why the totally ordered expectations are satisfied: the example just satisfies them in the order they are written. Being InSequence
, they retire as soon as they are satisfied.
However, the "partially ordered" scenario doesn't work because call #1 will satisfy expectation #3, then call #2 will match against expectation #2, which can't be met because it has expectation #1 as precondition. Even though technically, expectations #1 and #3 are identical, they are satisfied in reverse order of writing, since they don't belong to the same ordering, hence the failure.
I have the feeling that this phenomenon is not well enough documented by Google Mock. I'm still looking for a better formalization. I suspect that there's something wrong with the "partial order" concept as used here.