3.9 KiB
Mock Callbacks
Callbacks ("base/callback.h"
) are widely used in google3
to package data and
logic together. Sometimes you want to test how your code invokes callbacks (with
what arguments, how many times, in which order, and etc). This is a job cut out
for mock callbacks.
"testing/base/public/mock-callback.h"
defines a class template to mock
callbacks. Given arbitrary types R
, T1
, ..., and Tn
, class
MockCallback<R(T1, ..., Tn)>
mocks a callback that takes arguments of type
T1
, ..., and Tn
, and returns type R
, which can be void
. This class is
derived from its corresponding abstract callback classed defined in
"base/callback.h"
, for example:
MockCallback<void()>
inherits fromClosure
,MockCallback<void(int, double)>
inherits fromCallback2<int, double>
,MockCallback<int()>
derives fromResultCallback<int>
, andMockCallback<string(bool)>
derives fromResultCallback1<string, bool>
.
Compared with the various classes in "base/callback.h"
, the mock classes share
the same name and only differ in the template arguments, so you will never have
trouble remembering which is called what.
Like a real callback, a mock callback can be either single-use or permanent. A single-use mock callback will delete itself when invoked. A permanent mock callback will not and thus can be invoked many times - you have to make sure it is deleted somehow.
Since a mock object verifies all expectations on its mock methods in the
destructor, please link with //base:heapcheck
(it is already linked
automatically if you link with //testing/base/public:gtest_main
) to make sure
all mock callbacks
are properly deleted.
MockCallback<R(T1, ..., Tn)>
has a mock method OnRun()
with the signature:
R OnRun(T1, ..., Tn);
OnRun()
will be called whenever the mock callback is invoked. Note that we
don't name it Run()
to match the method in the base class, as doing so will
interfere with mocking single-use callbacks.
Finally, "mock-callback.h"
is a header-only library, so just include it and
go. Here's a complete example on how you use it:
#include "testing/base/public/mock-callback.h"
// 1. Import the necessary names from the testing name space.
using ::testing::_;
using ::testing::MockCallback;
using ::testing::NotNull;
using ::testing::NewMockCallback;
using ::testing::NewPermanentMockCallback;
using ::testing::SetArgPointee;
TEST(FooTest, DoesBar) {
// 2. Create a single-use mock callback using NewMockCallback(), or
// a permanent mock callback using NewPermanentMockCallback().
MockCallback<string(int n, bool show_sign)>* show_int = NewMockCallback();
std::unique_ptr<MockCallback<void(int* count)> > get_count(
NewPermanentMockCallback());
// 3. Set expectations on the OnRun() method of the mock callbacks.
EXPECT_CALL(*show_int, OnRun(5, true))
.WillOnce(Return("+5"));
EXPECT_CALL(*get_count, OnRun(NotNull()))
.WillOnce(SetArgPointee<0>(1))
.WillOnce(SetArgPointee<0>(2));
// 4. Exercise code that uses the mock callbacks. The single-use
// mock callback show_int will be verified and deleted when it's
// called. Link with //base:heapcheck to make sure it is not
// leaked.
Foo(5, show_int, get_count.get());
// Foo()'s signature:
// void Foo(int n, ResultCallback2<string, int, bool>* show_int,
// Callback1<int*>* get_count);
// 5. The permanent mock callback will be verified and deleted here,
// thanks to the std::unique_ptr.
}
Did you notice that you don't specify the types when calling NewMockCallback()
and NewPermanentMockCallback()
? Apparently they can read your mind and know
the type of the mock callback you want. :-)
(Seriously, these functions figure out their return types from the left-hand-side of the assignment or the initialization, with the help of some template tricks. But you don't need to understand how they work in order to use mock callbacks.)