9

Consider the case where a certain mocked function is expected to be called several times, each time with a different value in a certain parameter. I would like to validate that the function was indeed called once and only once per value in a certain list of values (e.g. 1,2,5).

On the other hand, I would like to refrain from defining a sequence as that would dictate a certain order, which is an implementation detail I would like to keep free.

Is there some kind of matcher, or other solution for this case?

I'm not sure if this influences the solution in any way but I do intend to use WillOnce(Return(x)) with a different x per value in the list above.

273K
  • 29,503
  • 10
  • 41
  • 64
Jonathan Livni
  • 101,334
  • 104
  • 266
  • 359
  • Related: https://stackoverflow.com/questions/44034633/google-mock-can-i-call-expect-call-multiple-times-on-same-mock-object/60905880#60905880 – Gabriel Staples Mar 29 '20 at 22:08

2 Answers2

14

By default gMock expectations can be satisfied in any order (precisely for the reason you mention -- so you don't over specify your tests).

In your case, you just want something like:

EXPECT_CALL(foo, DoThis(1));
EXPECT_CALL(foo, DoThis(2));
EXPECT_CALL(foo, DoThis(5));

And something like:

foo.DoThis(5);
foo.DoThis(1);
foo.DoThis(2);

Would satisfy those expectations.

(Aside: If you did want to constrain the order, you should use InSequence: https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#expecting-ordered-calls-orderedcalls)

Shalom Craimer
  • 20,659
  • 8
  • 70
  • 106
smehmood
  • 1,906
  • 12
  • 9
  • I must have been tiered when writing that question. I'll leave it posted for all those other tiered programmers :) – Jonathan Livni May 06 '11 at 11:47
  • Can't the EXPECT_CALL be more compact? Something like: EXPECT_CALL(foo, DoThis(Args<1, 2, 5>)); ? – xwl Nov 11 '16 at 08:41
  • @xwl, no. Remember that `EXPECT_CALL()` is a macro, and macro expansion is difficult enough as it is. I suspect what you are showing there would be impossible to implement via a macro. – Gabriel Staples Mar 28 '20 at 18:00
3

If you expect a function, DoThing, to be called with many different parameters, you can use the following pattern:

for (auto const param : {1, 2, 3, 7, -1, 2}){
    EXPECT_CALL(foo, DoThing(param));
}

This is particularly helpful if your EXPECT_CALL includes many parameters, of which only one is changing, or if your EXPECT_CALL includes many Actions to be repeated.

Joshua Ryan
  • 628
  • 5
  • 12
  • `EXPECT_CALL()` is a macro which expands in place. I'm pretty sure this will *not* work, as it creates one macro expansion instead of 6 unique macro expansions. Have you tested it to conclusively prove it works? – Gabriel Staples Mar 28 '20 at 18:06
  • @GabrielStaples yes, I've tested this many times. It's not relevant that EXPECT_CALL is a macro, or that the macro is only expanded once. For example, you can have a helper function that sets expectations based on parameters provided to that function. You can call that function as many times as you want. Gtest/Gmock does a good job of making copies of everything you pass into matchers and expectations. – Joshua Ryan Mar 29 '20 at 21:31
  • 1
    Thanks. Makes sense. I've upvoted it. Haven't tested it myself, but if it works it looks very useful. – Gabriel Staples Mar 29 '20 at 22:07
  • I use this pattern a lot, but a negative is that the output will reference "EXPECT_CALL(foo, DoThing(param));", i.e. "param" will not be expanded to indicate which param actually fails. You have to balance up the code saved versus the convenience of seeing what caused the failure. – dlanod Aug 20 '20 at 05:57