如何在单元测试中测试升压记录器输出?
How to test boost logger output in unit testing?
我的应用程序使用 BOOST_LOG_TRIVIAL
来记录消息。我认为检查测试 (gtest) 在给定场景中是否写入了正确的消息是很好的。
有没有办法以某种方式访问代码调用后写入的内容?还是首先必须以某种方式对其进行模拟?
我为此在谷歌上搜索了很多,但没有找到任何说明,所以要么我问错了问题,要么没有人认为应该这样做。
在您的 googletest 套件中,您可以使用 boost::log
设施
每个测试用例将 BOOST_LOG_TRIVIAL
消息重定向到一个文件。
在写完 BOOST_LOG_TRIVIAL
条你想要的消息后,你就可以
刷新文件,打开它,并检查它是否包含您期望的内容。
例如:
gtester.cpp
#include <gtest/gtest.h>
#include <boost/shared_ptr.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/trivial.hpp>
#include <string>
#include <fstream>
using sink_t = boost::log::sinks::synchronous_sink<boost::log::sinks::text_file_backend>;
struct boost_log_tester : ::testing::Test {
void SetUp() {
file_sink = boost::log::add_file_log("boost.log");
}
void TearDown() {
boost::log::core::get()->remove_sink(file_sink);
file_sink.reset();
}
protected:
boost::shared_ptr<sink_t> file_sink;
};
TEST_F(boost_log_tester,info_msg)
{
std::string msg = "An informational severity message";
BOOST_LOG_TRIVIAL(info) << msg;
file_sink->flush();
std::ifstream captured_cout("boost.log");
ASSERT_TRUE(captured_cout.good()) << "Failure executing test: Could not open `boost.log` for reading";
std::string cout_str;
std::getline(captured_cout,cout_str);
EXPECT_NE(cout_str.find(msg),std::string::npos);
}
TEST_F(boost_log_tester,error_msg)
{
std::string msg = "An error severity message";
BOOST_LOG_TRIVIAL(error) << msg;
file_sink->flush();
std::ifstream captured_cerr("boost.log");
ASSERT_TRUE(captured_cerr.good()) << "Failure executing test: Could not open `boost.log` for reading";
std::string cerr_str;
std::getline(captured_cerr,cerr_str);
EXPECT_NE(cerr_str.find(msg),std::string::npos);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
编译并link:
$ g++ -Wall -Wextra -DBOOST_LOG_DYN_LINK -c gtester.cpp
$ g++ -o gtester gtester.o -lboost_log -lboost_thread -lboost_system -lgtest -pthread
它的运行方式如下:
$ ./gtester
[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from boost_log_tester
[ RUN ] boost_log_tester.info_msg
[ OK ] boost_log_tester.info_msg (0 ms)
[ RUN ] boost_log_tester.error_msg
[ OK ] boost_log_tester.error_msg (2 ms)
[----------] 2 tests from boost_log_tester (2 ms total)
[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran. (2 ms total)
[ PASSED ] 2 tests.
根据 Mike 的回答,我认为创建文件的必要性是一个缺点,我做了一些研究并发现了这种使用字符串流的方式:
class boost_logger_test : public testing::Test
{
typedef boost::log::sinks::synchronous_sink<boost::log::sinks::text_ostream_backend> sink_t;
boost::shared_ptr<sink_t> streamSink;
std::stringstream ss;
public:
virtual void SetUp()
{
streamSink = boost::log::add_console_log(ss);
}
virtual void TearDown()
{
boost::log::core::get()->remove_sink(streamSink);
streamSink.reset();
}
std::vector<std::string> getLogMessages()
{
std::vector<std::string> messages;
std::string msg;
while (std::getline(ss, msg, '\n'))
{
messages.push_back(msg);
}
return messages;
}
}
然后您可以轻松地在测试中使用消息,例如:
ASSERT_THAT(getLogMessages(), ElementsAre("Just some log message"));
我的应用程序使用 BOOST_LOG_TRIVIAL
来记录消息。我认为检查测试 (gtest) 在给定场景中是否写入了正确的消息是很好的。
有没有办法以某种方式访问代码调用后写入的内容?还是首先必须以某种方式对其进行模拟?
我为此在谷歌上搜索了很多,但没有找到任何说明,所以要么我问错了问题,要么没有人认为应该这样做。
在您的 googletest 套件中,您可以使用 boost::log
设施
每个测试用例将 BOOST_LOG_TRIVIAL
消息重定向到一个文件。
在写完 BOOST_LOG_TRIVIAL
条你想要的消息后,你就可以
刷新文件,打开它,并检查它是否包含您期望的内容。
例如:
gtester.cpp
#include <gtest/gtest.h>
#include <boost/shared_ptr.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/trivial.hpp>
#include <string>
#include <fstream>
using sink_t = boost::log::sinks::synchronous_sink<boost::log::sinks::text_file_backend>;
struct boost_log_tester : ::testing::Test {
void SetUp() {
file_sink = boost::log::add_file_log("boost.log");
}
void TearDown() {
boost::log::core::get()->remove_sink(file_sink);
file_sink.reset();
}
protected:
boost::shared_ptr<sink_t> file_sink;
};
TEST_F(boost_log_tester,info_msg)
{
std::string msg = "An informational severity message";
BOOST_LOG_TRIVIAL(info) << msg;
file_sink->flush();
std::ifstream captured_cout("boost.log");
ASSERT_TRUE(captured_cout.good()) << "Failure executing test: Could not open `boost.log` for reading";
std::string cout_str;
std::getline(captured_cout,cout_str);
EXPECT_NE(cout_str.find(msg),std::string::npos);
}
TEST_F(boost_log_tester,error_msg)
{
std::string msg = "An error severity message";
BOOST_LOG_TRIVIAL(error) << msg;
file_sink->flush();
std::ifstream captured_cerr("boost.log");
ASSERT_TRUE(captured_cerr.good()) << "Failure executing test: Could not open `boost.log` for reading";
std::string cerr_str;
std::getline(captured_cerr,cerr_str);
EXPECT_NE(cerr_str.find(msg),std::string::npos);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
编译并link:
$ g++ -Wall -Wextra -DBOOST_LOG_DYN_LINK -c gtester.cpp
$ g++ -o gtester gtester.o -lboost_log -lboost_thread -lboost_system -lgtest -pthread
它的运行方式如下:
$ ./gtester
[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from boost_log_tester
[ RUN ] boost_log_tester.info_msg
[ OK ] boost_log_tester.info_msg (0 ms)
[ RUN ] boost_log_tester.error_msg
[ OK ] boost_log_tester.error_msg (2 ms)
[----------] 2 tests from boost_log_tester (2 ms total)
[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran. (2 ms total)
[ PASSED ] 2 tests.
根据 Mike 的回答,我认为创建文件的必要性是一个缺点,我做了一些研究并发现了这种使用字符串流的方式:
class boost_logger_test : public testing::Test
{
typedef boost::log::sinks::synchronous_sink<boost::log::sinks::text_ostream_backend> sink_t;
boost::shared_ptr<sink_t> streamSink;
std::stringstream ss;
public:
virtual void SetUp()
{
streamSink = boost::log::add_console_log(ss);
}
virtual void TearDown()
{
boost::log::core::get()->remove_sink(streamSink);
streamSink.reset();
}
std::vector<std::string> getLogMessages()
{
std::vector<std::string> messages;
std::string msg;
while (std::getline(ss, msg, '\n'))
{
messages.push_back(msg);
}
return messages;
}
}
然后您可以轻松地在测试中使用消息,例如:
ASSERT_THAT(getLogMessages(), ElementsAre("Just some log message"));