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
Do not set new expectations after verifying and clearing a mock after its use. Setting expectations after code that exercises the mock has undefined behavior. See Using Mocks in Testsfor more information.
Expectation Order By default, expectations can be matched in anyorder. If some or all expectations must be matched in a given order, you can use the Afterclauseor InSequenceclauseof EXPECT_CALL, or use an InSequenceobject. Verifying and Resetting a Mock
By default, expectations can be matched in anyorder. If some or all expectations must be matched in a given order, you can use the Afterclauseor InSequenceclauseof EXPECT_CALL, or use an InSequenceobject.
By default, an expectation can match a call even though an earlier expectation hasn’t been satisfied. In other words, the calls don’t have to occur in the order the expectations are specified. Sometimes, you may want all the expected calls to occur in a strict order. To say this in gMock is easy: using ::testing::InSequence; ...
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.
Looking at your question and your answer, I think your case is a typical example of DAG (directed acyclic graph) which can be solved by InSequence clause to EXPECT_CALL (not the InSeqeunce class from ::testing:: namespace). See gmock Cookbook explanation here. Example test provided in your answer can be solved this way:
Sequence s1, s2;
EXPECT_CALL(mock1, methodA(_)).InSequence(s1, s2);
EXPECT_CALL(mock2, methodX(_)).InSequence(s1);
EXPECT_CALL(mock2, methodY(_)).InSequence(s2);
The above test code will make sure methodA is called before methodX and methodY. Also, it doesn't care in which order are methodX and methodY called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With