g3_mock_callbacks.md 3.91 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#### 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 from `Closure`,
*   `MockCallback<void(int, double)>` inherits from `Callback2<int, double>`,
*   `MockCallback<int()>` derives from `ResultCallback<int>`, and
*   `MockCallback<string(bool)>` derives from `ResultCallback1<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:

```cpp
  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:

```cpp
#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.)