Search code examples
c++unit-testinggoogletest

C++ / GoogleTest - How to run Setup for each test in a link directory


I am trying to capture the stdout at the start of each individual test, and if the test fails, only then print the stdout. I need this to run for each TEST and TEST_F in a directory so I am looking if I can apply a global test fixture if possible to the main.

I can apply a global environment but this runs at the setup and tear down of the test runner. And I can get this working by adding the code to each of my many standard test fixtures but I was hoping for a global solution rather than changing each fixture.

struct dummyFixture : public ::testing::Test
{
    // --- Need to apply this globally ---
    void SetUp()
    {
        backup = std::cout.rdbuf();
        std::cout.rdbuf(testingSink.rdbuf());
    }
    void TearDown()
    {
        std::cout.rdbuf(backup);
        if (::testing::Test::HasFailure())
            std::cout << testingSink.str() << std::endl;
        testingSink.str(std::string());
    }
    private:
        std::stringstream testingSink;
        std::streambuf *backup;
};

TEST(dummyTest, test_pass)
{
    // should not print log to console
    std::cout << "DUMMY TEST" << std::endl;
    EXPECT_TRUE(true);
}
TEST_F(dummyFixture, test_fail)
{
    // should print log to console
    std::cout << "DUMMY TEST FIXTURE" << std::endl;
    EXPECT_TRUE(false);
}

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

Solution

  • Since you don't want to modify any of the text fixtures and you want to run this just like the SetUp() & TearDown() of the test fixture, you can try with below approach.

    class Logger
    {
     Logger()
        {
            backup = std::cout.rdbuf();
            std::cout.rdbuf(testingSink.rdbuf());
        }
        ~Logger()
        {
            std::cout.rdbuf(backup);
            if (::testing::Test::HasFailure())
                std::cout << testingSink.str() << std::endl;
            testingSink.str(std::string());
        }
        private:
            std::stringstream testingSink;
            std::streambuf *backup;
    };
    

    You can now derive all of your test classes(deriving from ::testing::test) from this Logger class.

    struct dummyFixture : public ::testing::Test, **public Logger**
    {
    };
    

    GTest also has methods CaptureStdout() & GetCapturedStdout() to get the captured stdout string, you can use them as well.

    This will make sure that you achieve what you are trying to do with minimal code changes.