summaryrefslogtreecommitdiffstats
path: root/googlemock/g3doc/includes/g3_testing_LOGs.md
blob: 6a86086a5107b30e428e653107ca75a4e6cbdf58 (plain)
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#### Testing LOG()s {#TestingLogs}

LOG()s are widely used in `google3` programs. They make it possible to diagnose
a server crash when you don't have the luxury of reproducing the bug. They are
also great as a [tool for refactoring](http://go/log-pin).

Often we need to test how a piece of code calls LOG()s. Traditionally, this has
been done using [golden files](http://go/log-pin), which is tedious to set up
and brittle (what if a library you depend on starts to generate its own logs?).
The [`ScopedMemoryLog`](http://go/gunit-faq-scoped-mock-log) class was created
to allow writing robust LOG tests, but using it beyond the most basic scenario
can be awkward.

With gMock we have a better solution. `testing/base/public/mock-log.h` defines a
mock log sink class `ScopedMockLog`. A `ScopedMockLog` object intercepts all
LOG()s (except `LOG(FATAL)`) while it is alive. This object has a mock method of
this signature:

```cpp
  void Log(LogSeverity severity, const string& path, const string& message);
```

This file comes with gUnit and gMock, so there is no need to add any dependency
to your `BUILD` rule in order to use it.

Here are some ideas on how to make use of it:

To test that the code generates exactly one warning message (and nothing else):

```cpp
using ::testing::_;
using ::testing::kDoNotCaptureLogsYet;
using ::testing::ScopedMockLog;
...
  ScopedMockLog log(kDoNotCaptureLogsYet);
  EXPECT_CALL(log, Log(WARNING, _, "Expected warning."));
  log.StartCapturingLogs();
  ... code that LOG()s ...
```

To test that a particular message is logged exactly once (but there can be other
log messages with different contents):

```cpp
using ::testing::_;
using ::testing::kDoNotCaptureLogsYet;
using ::testing::AnyNumber;
using ::testing::ScopedMockLog;
...
  ScopedMockLog log(kDoNotCaptureLogsYet);
  EXPECT_CALL(log, Log).Times(AnyNumber());
  EXPECT_CALL(log, Log(INFO, _, "Expected message"));
  log.StartCapturingLogs();
  ... code that LOG()s ...
```

To test that no `ERROR` is logged (but there can be other log messages with
different severities):

```cpp
using ::testing::_;
using ::testing::kDoNotCaptureLogsYet;
using ::testing::AnyNumber;
using ::testing::ScopedMockLog;
...
  ScopedMockLog log(kDoNotCaptureLogsYet);
  EXPECT_CALL(log, Log).Times(AnyNumber());
  EXPECT_CALL(log, Log(ERROR, _, _))
      .Times(0);
  log.StartCapturingLogs();
  ... code that LOG()s ...
```

To test that a particular message is logged at least once (and there can be
other log messages):

```cpp
using ::testing::_;
using ::testing::kDoNotCaptureLogsYet;
using ::testing::AnyNumber;
using ::testing::AtLeast;
using ::testing::ScopedMockLog;
...
  ScopedMockLog log(kDoNotCaptureLogsYet);
  EXPECT_CALL(log, Log).Times(AnyNumber());
  EXPECT_CALL(log, Log(INFO, _, "Expected message"))
      .Times(AtLeast(1));
  log.StartCapturingLogs();
  ... code that LOG()s ...
```

To test that three LOG()s occur sequentially:

```cpp
using ::testing::_;
using ::testing::kDoNotCaptureLogsYet;
using ::testing::InSequence;
using ::testing::ScopedMockLog;
...
  ScopedMockLog log(kDoNotCaptureLogsYet);
  {
     InSequence s;
     EXPECT_CALL(log, Log(INFO, _, "Log #1"));
     EXPECT_CALL(log, Log(WARNING, _, "Log #2"));
     EXPECT_CALL(log, Log(INFO, _, "Log #3"));
  }
  log.StartCapturingLogs();
  ... code that LOG()s ...
```

To test that the log message contains a certain sub-string:

```cpp
using ::testing::_;
using ::testing::kDoNotCaptureLogsYet;
using ::testing::HasSubstr;
using ::testing::ScopedMockLog;
...
  ScopedMockLog log(kDoNotCaptureLogsYet);
  EXPECT_CALL(log, Log(WARNING, _, HasSubstr("needle")));
  log.StartCapturingLogs();
  ... code that LOG()s ...
```

To test that a given module generates a specific log:

```cpp
using ::testing::kDoNotCaptureLogsYet;
using ::testing::ScopedMockLog;
...
  ScopedMockLog log(kDoNotCaptureLogsYet);
  EXPECT_CALL(log, Log(WARNING, "path/to/my_module.cc", "Expected warning."));
  log.StartCapturingLogs();
  ... code that LOG()s ...
```

To test that code doesn't log anything at all:

```cpp
using ::testing::_;
using ::testing::kDoNotCaptureLogsYet;
using ::testing::ScopedMockLog;
...
  ScopedMockLog log(kDoNotCaptureLogsYet);
  EXPECT_CALL(log, Log).Times(0);
  log.StartCapturingLogs();
  ... code that does not LOG() ...
```

**Warning:** For robust tests, either ignore unexpected logs (loose), or ignore
logs in other modules (tight), otherwise your test may break if their logging
changes.

```cpp
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::kDoNotCaptureLogsYet;
using ::testing::Not;
using ::testing::ScopedMockLog;

// ...

// Simple robust setup, ignores unexpected logs.
  ScopedMockLog log(kDoNotCaptureLogsYet);
  EXPECT_CALL(log, Log).Times(AnyNumber());  // Ignore unexpected logs.
  EXPECT_CALL(log, Log(ERROR, "path/to/my_file.cc", _))
      .Times(3);  // Verifies logs from my_file.cc.
  log.StartCapturingLogs();
  // ... code that LOG()s ...

// ...

// Tighter alternative.
  ScopedMockLog log(kDoNotCaptureLogsYet);
  EXPECT_CALL(log, Log(_, Not("path/to/my_file.cc"), _))
      .Times(AnyNumber());  // Ignores other modules.
  EXPECT_CALL(log, Log(ERROR, "path/to/my_file.cc", _))
      .Times(3);  // Verifies logs from my_file.cc.
  log.StartCapturingLogs();
  // ... code that LOG()s ...
```

To test `LOG(DFATAL)`, use
[`EXPECT_DFATAL`](/third_party/googletest/googletest/docs/google3_faq#testing-death-in-debug-mode)
instead.
OpenPOWER on IntegriCloud