c++googletestspdlog

How can I read spdlog output in a google test


I am on the latest commit of spdlog (there is an issue regarding std output, apparently resolved), and am switching my output from std::cout to spdlog.

My google tests redirect std::cout so I can check the output of stub functions:

class MyTest : public testing::Test
{
protected:
        void SetUp() override
        {            
            sbuf = std::cout.rdbuf();
            std::cout.rdbuf(buffer.rdbuf());
            auto console = spdlog::stdout_color_mt("console");
            auto err_logger = spdlog::stderr_color_mt("stderr");            
        }
        void TearDown() override
        {
            std::cout.rdbuf(sbuf);         
        }
        std::stringstream buffer;
        std::streambuf* sbuf;
}

then use as follows inside a test;

doSomethingThatWritesToStdOut();
std::string teststr = buffer.str();
EXPECT_TRUE(teststr.find("Some output string") != std::string::npos);

This doesn't work when I change the content of doSomethingThatWritesToStdOut to

spdlog::get("console")->debug("Some output string\n");

The teststr value is empty.. If I do the following

 spdlog::get("console")->debug("Some output string\n");
 std::cout << "Some output string\n";

Then I can see one instance of "Some output string" in teststr. How can I capture the output of this logger (or change the logger) so I can test in google tests?


Solution

  • As I've mentioned in the comments, I had thought spdlog output to std::cout due to an earlier issue, but in fact that was related to stdout.. (facepalm)

    This is nice and easy, it turns out! By using an ostream_sink, the output can be sent to a specified ostream;

    I set a logger up in my test SetUp() function as follows

                auto ostream_logger = spdlog::get("gtest_logger");
                if (!ostream_logger)
                {
                    auto ostream_sink = std::make_shared<spdlog::sinks::ostream_sink_st>(_oss);
                    ostream_logger = std::make_shared<spdlog::logger>("gtest_logger", ostream_sink);
                    ostream_logger->set_pattern(">%v<");
                    ostream_logger->set_level(spdlog::level::debug);
                }
                spdlog::set_default_logger(ostream_logger);
    

    where _oss is a std::ostringstream.

    Then my tests just look at the contents of _oss, and clear it after each check:

            std::string test = _oss.str();
            // check the derived class is constructed
            EXPECT_TRUE(test.find("Constructing test class") != std::string::npos);
            _oss.str("");
    

    The existing code using spdlog::debug, spdlog::trace etc doesn't need changing at all.