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.
 |