Reputation: 939
I have a situation where I want to check if a mock object method was called with parameter X, but the test gets access to X only after the mock is invoked, so I can't set an EXPECT_CALL beforehand.
E.g.
// The class I'm testing.
class Maker
{
void register(Listener& lis);
Obj& make()
{
// make new Obj o
// call created(o) on registered Listener
// return o
}
}
class Listener
{
virtual void created(Obj& o) = 0;
}
// The test
Listener lis;
Maker maker;
maker.register(lis);
Obj& o = maker.make();
// Check that lis was invoked using param o...how?
Can i do this with google mocks? What is the most elegant / readable way of doing this using google mocks?
Obviously I can make my own MockListener which will record invocation parameters, instead of using google mocks. But I'm hoping google mocks would preesnt a more readable mechanism, similar to EXPECT_CALL.
Upvotes: 3
Views: 6774
Reputation: 6972
You can use the SaveArg<N>
action to save the value of the parameter with which Listener::created(Obj&)
is called, so you can compare its value to the one returned by maker.make()
afterwards.
This will require that you provide equality operator for class Obj
, i.e. bool operator==(const Obj&, const Obj&)
.
Your test could then look like this:
class ListenerMock : public Listener
{
public:
MOCK_METHOD1(created, void(Obj&));
};
TEST(MakerTest, make_registersObject)
{
ListenerMock lis;
Maker maker;
maker.register(lis);
Obj createdArg;
EXPECT_CALL(lis, created(_))
.Times(1)
.WillOnce(SaveArg<0>(&createdArg));
Obj& o = maker.make();
ASSERT_EQ(createdArg, o);
}
Upvotes: 7
Reputation: 939
I think the answer is that "this is not what google mocks was made for."
It seems it's made for "interaction-based testing" not "state-based testing", as explained here:
With Google Mock, you can create mocks in C++ easily. And people might be tempted to use them everywhere. Sometimes they work great, and sometimes you may find them, well, a pain to use. So, what's wrong in the latter case?
When you write a test without using mocks, you exercise the code and assert that it returns the correct value or that the system is in an expected state. This is sometimes called "state-based testing".
Mocks are great for what some call "interaction-based" testing: instead of checking the system state at the very end, mock objects verify that they are invoked the right way and report an error as soon as it arises, giving you a handle on the precise context in which the error was triggered. This is often more effective and economical to do than state-based testing.
If you are doing state-based testing and using a test double just to simulate the real object, you are probably better off using a fake. Using a mock in this case causes pain, as it's not a strong point for mocks to perform complex actions. If you experience this and think that mocks suck, you are just not using the right tool for your problem. Or, you might be trying to solve the wrong problem. :-)
Upvotes: -2