目前我正在使用 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/