【问题标题】:BOOST_CHECK_NO_THROW how to get exception message printedBOOST_CHECK_NO_THROW 如何打印异常消息
【发布时间】:2013-02-28 10:36:30
【问题描述】:

当我使用测试方法时

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()

【问题讨论】:

  • 写到哪里? Boost Tests 用于检查代码是否损坏,而不是用于调试代码。它坏了吗?它是布尔值:true 或 false。
  • (1) 写入标准输出(控制台或 xml 文件,取决于测试运行器的命令行参数) (2) 如果抛出异常,是的,它被破坏了。但是,如果可以看到异常消息(what() 的输出),则可以更快地找出错误的来源。
  • 是的,但为什么呢?测试确实表明代码被破坏了:它在不应该抛出的地方抛出了异常。下一步是采取并修复代码或测试,而不是创建用垃圾填充控制台的详细 XML 文件。
  • 嗯,好的。我认为更快地找到错误会很好。我的测试使用数据库(实际上,没有模拟对象),并且测试可能由于不同的原因而失败(不仅是由于错误的类或测试代码)。我相信由于“高度可定制”的提升测试框架可能会有一个解决方案,但我可能最终没有使用这个不错的BOOST_AUTO_*()。但是谢谢 Tiib!
  • 为什么,@ÖöTiib?你宁愿让你的医生告诉你“我发现你有问题”。或“我发现你的膝盖有问题。”?如果语句没有包装在BOOST_<LEVEL>_NO_THROW 中,单元测试框架会打印异常消息。使用断言所提供的信息不应该比没有它们时获得的信息

标签: c++ unit-testing boost-test


【解决方案1】:

我发现自己对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】:

我在 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没有变化就可以工作

异常消息将在测试输出中标记为错误之前打印。这首先看起来有点可怜,这就是为什么我通过将“---”写入 outstream 来对输出进行分组以增强阅读效果。但是 BOOST_CHECK_IMPL 之后的代码永远不会到达。

上面的解决方案对我来说很好用。随意使用,如果你有同样的愿望 =)

(使用CDash进行ctest输出,别忘了增加测试输出限制,或者简单禁用限制:http://web.archiveorange.com/archive/v/5y7PkVuHtkmVcf7jiWol

【讨论】:

    【解决方案3】:

    解决方案 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;
        }
    }
    

    那么你的测试用例会这样写:

    BOOST_AUTO_TEST_CASE(case1)
    {
        BOOST_CHECK_NO_THROW( middle_man(0) );
    }
    

    这种方法的一个缺点是您需要为每个method_to_test 使用不同的middle_man 函数。

    解决方案 2。

    使用装饰器,见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)() );
    }
    
    

    【讨论】:

      猜你喜欢
      • 2011-07-14
      • 2013-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-18
      • 2013-03-30
      • 1970-01-01
      • 2014-03-04
      相关资源
      最近更新 更多