当我使用
测试方法时BOOST_CHECK_NO_THROW( method_to_test() );
并抛出异常,它显示 引发了异常,但从未发出异常的消息,如下所示:
test.cpp(14): error in "test": incorrect exception my_exception is caught
是否也可以打印异常消息,即my_exception.what()
返回的字符串? my_exception
源自std::exception
并重载what()
。
答案 0 :(得分:6)
我在boost头中读了一下,并在我自己的头文件中重新定义了BOOST_CHECK_NO_THROW_IMPL,我在项目中使用它重新定义了boost行为。现在它看起来像这样:
#ifndef _CATCH_BOOST_NO_THROW_H_
#define _CATCH_BOOST_NO_THROW_H_
#include <boost/test/unit_test.hpp>
#include <sstream>
#include <string>
#define BOOST_CHECK_NO_THROW_IMPL( S, TL ) \
try { \
S; \
BOOST_CHECK_IMPL( true, "no exceptions thrown by " BOOST_STRINGIZE( S ), TL, CHECK_MSG ); } \
catch( const std::exception & e ) { \
std::stringstream ss; \
ss << std::endl \
<< "-----------------------------------------------" << std::endl \
<< "test case: " << boost::unit_test::framework::current_test_case().p_name << std::endl \
<< std::endl << "exception message: " << e.what() << std::endl; \
BOOST_TEST_MESSAGE(ss.str()); \
BOOST_CHECK_IMPL( false, "exception thrown by " BOOST_STRINGIZE( S ), TL, CHECK_MSG ); \
} \
catch( ... ) { \
std::stringstream ss; \
ss << std::endl \
<< "-----------------------------------------------" << std::endl \
<< "test case: " << boost::unit_test::framework::current_test_case().p_name << std::endl \
<< std::endl << "exception message : <unknown exception>" << std::endl; \
BOOST_TEST_MESSAGE(ss.str()); \
BOOST_CHECK_IMPL( false, "exception thrown by " BOOST_STRINGIZE( S ), TL, CHECK_MSG ); \
} \
/**/
#define BOOST_WARN_NO_THROW( S ) BOOST_CHECK_NO_THROW_IMPL( S, WARN )
#define BOOST_CHECK_NO_THROW( S ) BOOST_CHECK_NO_THROW_IMPL( S, CHECK )
#define BOOST_REQUIRE_NO_THROW( S ) BOOST_CHECK_NO_THROW_IMPL( S, REQUIRE )
#endif // _CATCH_BOOST_NO_THROW_H_
缺点是:只要BOOST _ * _ NO_THROW
没有变化,它就会起作用和
在测试输出中将异常消息标记为错误之前,将打印该异常消息。这看起来有点不稳定,这就是为什么我通过将“---”写入流出来对输出进行分组以增强读数。但是永远不会达到BOOST_CHECK_IMPL之后的代码。
上面的解决方案对我来说非常好。随意使用,如果你有相同的威士忌=)
(使用CDash进行ctest输出,不要忘记增加测试输出限制,或者简单地禁用限制:http://web.archiveorange.com/archive/v/5y7PkVuHtkmVcf7jiWol)
答案 1 :(得分:5)
我发现自己对BOOST_REQUIRE_NO_THROW
的同样问题感到恼火。我只需删除BOOST_REQUIRE_NO_THROW
就解决了这个问题。这导致输出如:
unknown location(0): fatal error in "TestName": std::runtime_error: Exception message
并中止测试(但继续下一个文本),这就是我想要的。如果您想使用BOOST_CHECK_NO_THROW或BOOST_WARN_NO_THROW,这没有多大帮助。
答案 2 :(得分:0)
使用捕获异常的包装器方法,然后打印错误消息,然后重新引发,以便BOOST
可以报告该错误:
void method_to_test(int s)
{
if(s==0)
throw std::runtime_error("My error message");
}
void middle_man(int x)
{
try
{
method_to_test(x);
}catch(std::exception& e)
{
std::stringstream mes;
mes << "Exception thrown: " << e.what();
BOOST_TEST_MESSAGE(mes.str());// BOOST_ERROR(mes.str());
throw;
}
}
然后您的测试用例将显示为:
BOOST_AUTO_TEST_CASE(case1)
{
BOOST_CHECK_NO_THROW( middle_man(0) );
}
此方法的缺点是您需要为每个middle_man
使用不同的method_to_test
函数。
使用装饰器,请参见此answer, 就像以前的解决方案中的包装器一样。
template <class> struct Decorator;
template<class R,class ... Args>
struct Decorator<R(Args ...)>
{
std::function<R(Args ...)> f_;
Decorator(std::function<R(Args ...)> f):
f_{f}
{}
R operator()(Args ... args)
{
try
{
f_(args...);
}catch(std::exception& e)
{
std::stringstream mes;
mes << "Exception thrown: " << e.what();
BOOST_TEST_MESSAGE(mes.str());
throw;
}
}
};
template<class R,class ... Args>
Decorator<R(Args...)> makeDecorator(R (*f)(Args ...))
{
return Decorator<R(Args...)>(std::function<R(Args...)>(f));
}
然后您的测试用例将如下所示:
BOOST_AUTO_TEST_CASE(case2)
{
BOOST_CHECK_NO_THROW( makeDecorator(method_to_test)(0) );
BOOST_CHECK_NO_THROW( makeDecorator(another_method_to_test)() );
}