Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to capture stdout/stderr with googletest?

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.

like image 242
Jan Rüegg Avatar asked Sep 27 '10 11:09

Jan Rüegg


5 Answers

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.

like image 28
Wgaffa Avatar answered Nov 06 '22 22:11

Wgaffa


Googletest offers functions for this:

testing::internal::CaptureStdout();
std::cout << "My test";
std::string output = testing::internal::GetCapturedStdout();
like image 75
Heinzi Avatar answered Nov 06 '22 23:11

Heinzi


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.

like image 7
Flexo Avatar answered Nov 06 '22 23:11

Flexo


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);
    ...
 }
like image 4
Raedwald Avatar answered Nov 06 '22 23:11

Raedwald


Putting Wgaffa's suggestion (which I like) to a Google Test fixture, one might write:

namespace {

    class MyTestFixture : public ::testing::Test {
    protected:
        MyTestFixture() : sbuf{nullptr} {
            // intentionally empty
        }

        ~MyTestFixture() override = default;

        // Called before each unit test
        void SetUp() override {
            // Save cout's buffer...
            sbuf = std::cout.rdbuf();
            // Redirect cout to our stringstream buffer or any other ostream
            std::cout.rdbuf(buffer.rdbuf());
        }

        // Called after each unit test
        void TearDown() override {
            // When done redirect cout to its old self
            std::cout.rdbuf(sbuf);
            sbuf = nullptr;
        }

        // The following objects can be reused in each unit test

        // This can be an ofstream as well or any other ostream
        std::stringstream buffer{};
        // Save cout's buffer here
        std::streambuf *sbuf;
    };

    TEST_F(MyTestFixture, StackOverflowTest) {
        std::string expected{"Hello"};
        // Use cout as usual
        std::cout << expected;
        std::string actual{buffer.str()};
        EXPECT_EQ(expected, actual);
    }
} // end namespace

like image 1
Jim Daehn Avatar answered Nov 06 '22 23:11

Jim Daehn