c++ - CppUnit 期望带有 Assert Throw 的异常编译时带有警告 C4127

标签 c++ unit-testing compiler-warnings cppunit c4127

目前我正在使用 CppUnit 用 C++ 编写单元测试。最近我需要使用 CppUnits 宏检查特定情况下是否引发异常:

CPPUNIT_ASSERT_THROW(
    boost::get<FooClassInBoostVariant>(m_boostVariantFooOrBar),
    boost::bad_get);

测试编译过程中的警告让我感到惊讶(在 VS2010 上,但在其他编译器上也会出现警告......):

warning C4127: conditional expression is constant

我查看了 CppUnit 的宏定义,发现了以下内容:

do {                                                            \
  bool cpputExceptionThrown_ = false;                           \
  try {                                                         \
     expression;                                                \
  } catch ( const ExceptionType & ) {                           \
     cpputExceptionThrown_ = true;                              \
  }                                                             \
                                                                \
  if ( cpputExceptionThrown_ )                                  \
     break;                                                     \
                                                                \
  CPPUNIT_NS::Asserter::fail(                                   \
                 "Expected exception: " #ExceptionType          \
                 " not thrown.",                                \
                 CPPUNIT_SOURCELINE() );                        \
} while ( false )

嗯,我完全理解这是如何工作的,do while 循环只执行一次,因为 false,并且break 用于不执行 Asserter::fail() 部分。但他们为什么要这样做呢?当然,它会触发编译器警告,因为 while 循环的中断条件显然总是“假”。但是有没有更优雅的方法来做到这一点呢?我通常坚持无警告编译原则,所以这真的让我很烦恼。

所以我的问题是,他们为什么不这样实现:

{                                                               \
  bool cpputExceptionThrown_ = false;                           \
  try {                                                         \
    expression;                                                 \
  } catch ( const ExceptionType & ) {                           \
    cpputExceptionThrown_ = true;                               \
  }                                                             \
                                                                \
  if ( !cpputExceptionThrown_ ) {                               \
    CPPUNIT_NS::Asserter::fail(                                 \
                 "Expected exception: " #ExceptionType          \
                 " not thrown.",                                \
                 CPPUNIT_SOURCELINE() );                        \
  }                                                             \
}

提前致谢!

-汉内斯

最佳答案

原因是使断言成为一个陈述。考虑宏的这两种用途:

CPPUNIT_ASSERT_THROW(foo(), MyException);  // a
CPPUNIT_ASSERT_THROW(foo(), MyException)   // b - without trailing `;`!
doSomething();

使用他们的代码,您会收到 //b 错误,因为代码扩展为 do { ... } while (false) doSomething(); - 条件后面会缺少 ;

使用您的代码,//b 会很乐意编译,但 //a 可能会给您一个“空语句”警告,因为该行将扩展为 { ... };,在 block 后面添加多余的 ;

为什么他们强制你使用//a我不知道 - 但我更喜欢//b因为它只是每行后面都有一个 ; 。人们不必区分带断言的行和普通语句。

PS: 我不确定,但 { ... } block 和允许放置断言的 do {...} while(false) 语句之间可能存在更多差异在不允许使用简单 block 的地方使用宏。

编辑:使用 C++11,您可以使用 lambda(在一个地方定义并调用它):

#define CPPUNIT_ASSERT_THROW(expression, ExceptionType)         \
[&]() -> void {                                                 \
  bool cpputExceptionThrown_ = false;                           \
  try {                                                         \
     expression;                                                \
  } catch ( const ExceptionType & ) {                           \
     cpputExceptionThrown_ = true;                              \
  }                                                             \
                                                                \
  if ( cpputExceptionThrown_ )                                  \
     return;                                                    \
                                                                \
  CPPUNIT_NS::Asserter::fail(                                   \
                 "Expected exception: " #ExceptionType          \
                 " not thrown.",                                \
                 CPPUNIT_SOURCELINE() );                        \
}() 

但是,可能有一些警告,例如由于 lambda 捕获了您在表达式中使用的变量。

关于c++ - CppUnit 期望带有 Assert Throw 的异常编译时带有警告 C4127,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15333524/

相关文章:

c++ - 为什么 gcc 仅针对统一初始化警告缩小转换?

c - 当使用 -Wmissing-prototypes 时,如何抑制 GCC 对中断例程没有原型(prototype)的警告?

java - SPOCK:如何模拟供应商行为

asp.net - 如何编写单元测试来测试 ASP.NET Web 表单应用程序的 CSRF 漏洞?

c++ - 数据转换解决方案

c++ - 异步是否总是在 C++ 中使用另一个线程/核心/进程?

javascript - 预期等于结果时出现不可变的 Chai 断言错误

c++ - 在 Visual Studio 2017(VC++) 的链接阶段禁用库警告是否安全?

c++ - 对动态大小的对象进行排序

c# - RefCount 在 AtlUnadvise 调用后保持不变