Google Mock - How to Call Expect_Call Multiple Times on Same Mock Object

google mock - can I call EXPECT_CALL multiple times on same mock object?

Yes, you can call EXPECT_CALL on the same mock object multiple times. As long as you assure that all EXPECT_CALL were called before the mocked methods were actually used. Otherwise your test will rely on undefined behavior. From ForDummies:

Important note: gMock requires expectations to be set before the mock functions are called, otherwise the behavior is undefined. In particular, you mustn't interleave EXPECT_CALL()s and calls to the mock functions.

How multiple calls will be handled? The documentation is really straightforward. From ForDummies:

By default, when a mock method is invoked, Google Mock will search the
expectations in the reverse order they are defined, and stop when an
active expectation that matches the arguments is found (you can think
of it as "newer rules override older ones.").

Let's consider what this means for the gMock user, by checking some examples. I assume that we have a file with following header:

#include <gmock/gmock.h>

using namespace ::testing;

struct SomeMock
{
MOCK_CONST_METHOD1(foo, void(int));
};

The simplest example of passing test that calls EXPECT_CALL multiple times:

TEST(Examples, DifferentArgumentsGoingToBeOk)
{
SomeMock mock;

EXPECT_CALL(mock, foo(4)).Times(1); // exp#1
EXPECT_CALL(mock, foo(5)).Times(1); // exp#2

mock.foo(4); // call#1
mock.foo(5); // call#2
}

The tests works intuitively:

  • call#1 does not match with exp#2 so exp#1 is tried and matches.
  • call#2 matches with exp#2.

Both calls matched exactly once, thus they are considered satisfied and the test passes.

The tricky part starts when multiple EXPECT_CALL are able to match the call. Let's consider the following example:

TEST(Examples, TheSameArgumentsGoingToFail) // Test fails!
{
SomeMock mock;

EXPECT_CALL(mock, foo(4)).Times(1); //exp#1
EXPECT_CALL(mock, foo(4)).Times(1); //exp#2

mock.foo(4); // call#1
mock.foo(4); // call#2
}
  • The call#1 matches the exp#2. gMock stops at first matched expectation, it won't check the exp#1 at all.
  • The call#2 matches the exp#2. Again the exp#1 does not have chance to be matched.

As a result the test fails as the exp#2 gets matched twice instead of once and exp#1 is not matched at all. All that is printed in the test output:

/tmp/so/main.cpp:26: Failure // exp#2
Mock function called more times than expected - returning directly.
Function call: foo(4)
Expected: to be called once
Actual: called twice - over-saturated and active
/tmp/so/main.cpp:25: Failure // exp#1
Actual function call count doesn't match EXPECT_CALL(mock, foo(4))...
Expected: to be called once
Actual: never called - unsatisfied and active

Also, it is important, that adding new expectancy won't disable or remove old ones. They are still able to fail your test!

TEST(Examples, NewExpectCallDoesNotEraseThePreviousOne) // Test fails!
{
SomeMock mock;

EXPECT_CALL(mock, foo(4)).Times(1); // exp#1
EXPECT_CALL(mock, foo(4)).Times(2); // exp#2

mock.foo(4); // call#1
mock.foo(4); // call#2
}

Both call#1 and call#2 matches the exp#2. As a result the exp#2 is satisfied, but the test will fail as exp#1 was not matched enough times.

If for some reason, you need to write a test like TheSameArgumentsGoingToFail, you can use a number of techniques to prevent exp#2 from matching second time. Please refer to the documentation InSequence usage, RetiresOnSaturation:

TEST(Examples, InSequenceExample)
{
SomeMock mock;

Sequence seq;

EXPECT_CALL(mock, foo(4)).Times(1).InSequence(seq); //exp#1
EXPECT_CALL(mock, foo(4)).Times(1).InSequence(seq); //exp#2

mock.foo(4); // call#1
mock.foo(4); // call#2
}

TEST(Examples, InSequenceExampleSecondApproach)
{
SomeMock mock;

InSequence seq;

EXPECT_CALL(mock, foo(4)).Times(1); //exp#1
EXPECT_CALL(mock, foo(4)).Times(1); //exp#2

mock.foo(4); // call#1
mock.foo(4); // call#2
}

TEST(Examples, RetiresOnSaturationExample)
{
SomeMock mock;

EXPECT_CALL(mock, foo(4)).Times(1); //exp#1
EXPECT_CALL(mock, foo(4)).Times(1).RetiresOnSaturation(); //exp#2

mock.foo(4); // call#1
mock.foo(4); // call#2
}

TEST(Examples, AfterExample)
{
SomeMock mock;

auto& exp1 = EXPECT_CALL(mock, foo(4)).Times(1); //exp#1
EXPECT_CALL(mock, foo(4)).Times(1).After(exp1); //exp#2

mock.foo(4); // call#1
mock.foo(4); // call#2
}

Google Mock: multiple expectations on same function with different parameters

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)

Avoid matching .WillOnce multiple times in Google Mock

using testing::InSequence;

MyObject obj;

{
InSequence s;
EXPECT_CALL(obj, myFunction(_))
.Times(3)
.WillRepeatedly(Return(1));
EXPECT_CALL(obj, myFunction(_))
.WillRepeatedly(Return(-1));
}

Google Mock, expect call between 2 given numbers

Try Between from https://github.com/google/googletest/blob/master/googlemock/docs/cheat_sheet.md#cardinalities-cardinalitylist. It is exactly for the purpose of asserting that given call be called between m and n times.

google mock - how to say function must be called ONCE with a certain parameter but ok to be called many times with different parameters?

In Google Mock, later expectations override earlier ones (more details in the docs), so you can write this:

EXPECT_CALL(Mock_Obj, func(_)).Times(AnyNumber());
EXPECT_CALL(Mock_Obj, func("abc")).Times(1);

How can i call my mock method two times with two different argument value

Just do several WillOnce - one after another.

Like:

EXPECT_CALL(*mock.get(), GetSegment(refrenceId, _, _, _))
.WillOnce(DoAll(SetArgReferee<1>(numSegment), SetArgPointee<2>(points), SetArgPointee<3>(0))).
.WillOnce(DoAll(SetArgReferee<1>(numSegment), SetArgPointee<2>(points), SetArgPointee<3>(1)));

You can read in doc that WillOnce can be used several times in one EXPECT_CALL:

EXPECT_CALL(mock_object, method(matchers))
.WillOnce(action) *

The simplified example that works:

class MockMM
{
public:
MOCK_METHOD4(GetSegment, void(int refrenceId, int, int, int* a));
};

TEST(A, A)
{
MockMM mock;
EXPECT_CALL(mock, GetSegment(1, _, _, _))
.WillOnce(SetArgPointee<3>(0))
.WillOnce(SetArgPointee<3>(1));

int a;
int b;
mock.GetSegment(1, 1, 0, &a);
mock.GetSegment(1, 0, 1, &b);
ASSERT_EQ(0, a);
ASSERT_EQ(1, b);

}

You might also use sequences:

When you have a long chain of sequential expectations, it's easier to
specify the order using sequences, which don't require you to given
each expectation in the chain a different name. All expected calls in
the same sequence must occur in the order they are specified.

using ::testing::Sequence;
Sequence s1, s2;
...
EXPECT_CALL(foo, Reset())
.InSequence(s1, s2)
.WillOnce(Return(true));
EXPECT_CALL(foo, GetSize())
.InSequence(s1)
.WillOnce(Return(1));
EXPECT_CALL(foo, Describe(A<const char*>()))
.InSequence(s2)
.WillOnce(Return("dummy"));

Method from mock object not being called

In order for the polymorphic call to trigger, you need to pass a pointer or a reference to the base class, not the base class directly:

class MyObject
{
public:
MyObject(Parent& parent) :_parent(parent) {}
private: // members are usually private
Parent& parent;
};

this will allow you to have the proper method being called. Also, please keep in mind that Parent should outlive MyObject (so that you will avoid the dangling reference error).

Some additional notes: it's best to keep a pure virtual base class:

class ParentBase
{
public:
virtual ~ParentBase() = default;
virtual bool verify() const = 0;
};

and have both Parent and ParentMock to inferit from ParentBase. This enforces better separation of concerns - your classes will then deal with interfaces, not implementations.



Related Topics



Leave a reply



Submit