C++ BOOST\u CHECK\u NO\u抛出如何打印异常消息

C++ BOOST\u CHECK\u NO\u抛出如何打印异常消息,c++,unit-testing,boost-test,C++,Unit Testing,Boost Test,当我使用 BOOST_CHECK_NO_THROW( method_to_test() ); 当抛出异常时,它会显示抛出了异常,但不会显示如下异常消息: test.cpp(14): error in "test": incorrect exception my_exception is caught #ifndef _CATCH_BOOST_NO_THROW_H_ #define _CATCH_BOOST_NO_THROW_H_ #include <boost/test/unit

当我使用

BOOST_CHECK_NO_THROW( method_to_test() );
当抛出异常时,它会显示抛出了异常,但不会显示如下异常消息:

test.cpp(14): error in "test": incorrect exception my_exception is caught
#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_AUTO_TEST_CASE(case2)
{
    BOOST_CHECK_NO_THROW( makeDecorator(method_to_test)(0) );
    BOOST_CHECK_NO_THROW( makeDecorator(another_method_to_test)() );
}


是否也可以打印异常消息,即
my_exception.what()
返回的字符串
my_exception
源于
std::exception
和重载
what()

我发现自己对
BOOST\u REQUIRE\u NO\u THROW
的同样问题感到恼火。我通过简单地删除
BOOST\u REQUIRE\u NO\u THROW
解决了这个问题。这将产生如下输出:

unknown location(0): fatal error in "TestName": std::runtime_error: Exception message

并中止测试(但继续下一个文本),这正是我想要的。但是,如果您想使用BOOST\u CHECK\u NO\u THROW或BOOST\u WARN\u NO\u THROW,这没有多大帮助。

我在BOOST头文件中读了一些内容,并在我自己的头文件中重新定义了BOOST\u CHECK\u NO\u THROW\u IMPL,我在项目中使用它来重新定义BOOST行为。现在看起来是这样的:

test.cpp(14): error in "test": incorrect exception my_exception is caught
#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_AUTO_TEST_CASE(case2)
{
    BOOST_CHECK_NO_THROW( makeDecorator(method_to_test)(0) );
    BOOST_CHECK_NO_THROW( makeDecorator(another_method_to_test)() );
}

\ifndef\u捕获\u提升\u否\u抛出\H_
#定义"接球","助攻","否","掷球"
#包括
#包括
#包括
#定义增压、检查、否抛出、执行(S、TL)\
试试{\
S\
BOOST_CHECK_IMPL(true,“BOOST_STRINGIZE,TL,CHECK_MSG);”不会引发异常\
catch(const std::exception&e){\
std::stringstream-ss\
ss解决方案1。
使用捕获异常的包装器方法,然后打印错误消息,然后重新抛出,以便
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;
    }
}
这种方法的一个缺点是,对于每个
测试方法
,您都需要使用不同的
中间人
函数

解决方案2。 使用装饰器,看这个, 来完成前一个解决方案中的包装器所能做的事情

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测试用于检查代码是否已损坏,而不是调试代码。是否已损坏?它是布尔值:true或false。(1)写入标准输出(控制台或xml文件,取决于测试运行程序的命令行参数)(2)如果引发异常,则是已损坏。但如果可以看到异常消息(what()的输出)找出错误的来源更快。是的,但为什么?测试确实表明代码被破坏了:它会在不应该抛出的地方抛出异常。下一步是采取措施并修复代码或测试,而不是创建用垃圾填充控制台的详细XML文件。嗯,好的。我认为更快地找到错误会很好。我的测试使用了db(在现实中,没有模拟对象)和测试可能会因为不同的原因而失败(不仅仅是因为错误的类或测试代码)。我相信“高度可定制”的boost测试框架可能会有一个解决方案,但我可能最终不使用这个漂亮的
boost\u AUTO.*()
。但是谢谢你,蒂布!为什么,@Ö蒂布?你宁愿让你的医生告诉你“我发现你有问题。”还是“我发现你的膝盖有问题。”?如果语句没有包装在
BOOST\uu\u NO\u THROW
中,单元测试框架会打印异常消息。使用断言不会比没有断言时提供更少的信息。奇怪的是,这对我来说是最好的解决方案。