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.
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.
Googletest offers functions for this:
testing::internal::CaptureStdout();
std::cout << "My test";
std::string output = testing::internal::GetCapturedStdout();
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.
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);
...
}
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With