mirror of
https://github.com/google/googletest.git
synced 2025-03-28 09:13:57 +00:00
186 lines
5.3 KiB
Markdown
186 lines
5.3 KiB
Markdown
|
#### 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.
|