How to capture stdout/stderr with googletest?

52,766

Solution 1

I have used this snippet before to redirect cout calls to a stringstream when testing output. Hopefully it might spark some ideas. I've never used googletest before.

// This can be an ofstream as well or any other ostream
std::stringstream buffer;

// Save cout's buffer here
std::streambuf *sbuf = std::cout.rdbuf();

// Redirect cout to our stringstream buffer or any other ostream
std::cout.rdbuf(buffer.rdbuf());

// Use cout as usual
std::cout << "Hello World";

// When done redirect cout to its old self
std::cout.rdbuf(sbuf);

Before redirecting back to the original output use your google test to check the output in buffer.

Solution 2

Googletest offers functions for this:

testing::internal::CaptureStdout();
std::cout << "My test";
std::string output = testing::internal::GetCapturedStdout();

Solution 3

Avoiding having to do this is always a good design idea. If you really want to do it the following works:

#include <cstdio>
#include <cassert>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <iostream>

int main() {
   int fd = open("my_file.log", O_WRONLY|O_CREAT|O_TRUNC, 0660);
   assert(fd >= 0);
   int ret = dup2(fd, 1);
   assert(ret >= 0);
   printf("This is stdout now!\n");
   std::cout << "This is C++ iostream cout now!" << std::endl;
   close(fd);
}

To use stderr instead of stdout change the second argument to dup2 to be 2. For capturing without going via a file you could use a pipe pair instead.

Solution 4

Rather than do this, use dependency injection to remove the direct use of std::cout. In your test code use a mock object of class std:ostringstream as a mock object instead of the real std::cout.

So instead of this:

 void func() {
    ...
    std::cout << "message";
    ...
 }

 int main (int argc, char **argv) {
    ...
    func();
    ...
 }

have this:

 void func(std::ostream &out) {
    ...
    out << "message";
    ...
 }

 int main(int argc, char **argv) {
    ...
    func(std::cout);
    ...
 }
Share:
52,766
Jan Rüegg
Author by

Jan Rüegg

Computer scientist and passionate C++ developer.

Updated on July 05, 2022

Comments

  • Jan Rüegg
    Jan Rüegg almost 2 years

    Is it possible to capture the stdout and stderr when using the googletest framework?

    For example, I would like to call a function that writes errors to the console (stderr). Now, when calling the function in the tests, I want to assert that no output appears there.

    Or, maybe I want to test the error behaviour and want to assert that a certain string gets printed when I (deliberately) produce an error.

  • Jan Tojnar
    Jan Tojnar over 8 years
    probably the simplest possible solution
  • davidA
    davidA over 8 years
    This is only available for stdout, not stderr? There are death tests that capture stderr, but in many cases you may not be testing for process termination.
  • Heinzi
    Heinzi over 8 years
    testing::internal::CaptureStderr() also exists. Is used here for example: googletest.googlecode.com/svn/trunk/test/…
  • hamster on wheels
    hamster on wheels over 7 years
    the message is still printed on screen? how to suppress that?
  • Antoine Bolvy
    Antoine Bolvy over 7 years
    One should know that this is a private API and is therefore not supported. I'd advise against it
  • Nir Friedman
    Nir Friedman over 7 years
    I found this to segfault if called more than once, even in different tests, and therefore worthless.
  • zr.
    zr. about 6 years
    This solution won't work if the unit-under-test throws an exception.
  • Florin T.
    Florin T. over 5 years
    This doesn't work for googletest since gtest uses printf which goes straight to stdout, circumventing your redirect. But it is a nice solution if you want to intercept the output of cout << .... I would create a helper class though to automatically restore the original streambuf in the destructor...
  • Florin T.
    Florin T. over 5 years
    While this is a good idea in general, it won't work in his case because gtest is an external library (from his viewpoint) and he wants to capture the output of the framework without modifying the source code.
  • John Jiang
    John Jiang about 5 years
    This doesn't work for me. I still get no printout on the screen or in the log.
  • andreee
    andreee almost 5 years
    @NirFriedman it seems that one has to call ::testing::internal::CaptureStdout() prior to each capture.
  • Jim Daehn
    Jim Daehn over 4 years
    I've added a way one might use this with Google Test barring the scenario commented above.
  • Keshav Sahu
    Keshav Sahu over 2 years
    What if he/she has many functions that prints some error messages or logs? This won't work in that case as adding extra parameter just for capturing a stream is not a good idea. One thing he/she can do is to use global stream object and change/redirect it according to needs. std::cout, std::cerr and std::clog are such global objects. It's better to use std::cout and redirect it to another stream when needed.
  • Raedwald
    Raedwald over 2 years
    @KeshacSabu if there are many such functions, there are many design faults in the code to be fixed. Fixing them is a good idea.