精简版
你以错误的方式编写测试,编写测试你应该把断言放在测试(宏TEST
)或测试夹具(宏TEST_F
)中.
长版
1.真的发生了什么?
要找出真正的问题并不容易,因为Google Testing Framework使用隐藏真实代码的宏.要在宏替换后查看代码以执行预处理,如下所示:
g++ -E main.cpp -o main.p
使用时预处理的结果ASSERT_THROW
将如下所示(格式化后):
class my_exp {}; int main(int argc, char *argv[]) { switch (0) case 0: default: if (::testing::internal::ConstCharPtr gtest_msg = "") { bool gtest_caught_expected = false; try { if (::testing::internal::AlwaysTrue () ) { throw my_exp (); }; } catch (my_exp const &) { gtest_caught_expected = true; } catch (...) { gtest_msg.value = "Expected: throw my_exp() throws an exception of type my_exp.\n Actual: it throws a different type."; goto gtest_label_testthrow_7; } if (!gtest_caught_expected) { gtest_msg.value = "Expected: throw my_exp() throws an exception of type my_exp.\n Actual: it throws nothing."; goto gtest_label_testthrow_7; } } else gtest_label_testthrow_7: return ::testing::internal::AssertHelper (::testing::TestPartResult::kFatalFailure, "main.cpp", 7, gtest_msg.value) = ::testing::Message (); return 0; }
对于EXPECT_THROW
结果将是,除了一些区别一样:
else gtest_label_testthrow_7: ::testing::internal::AssertHelper (::testing::TestPartResult::kNonFatalFailure, "main.cpp", 7, gtest_msg.value) = ::testing::Message ();
2.好的,找到了不同行为的原因,让我们继续.
在文件src/gtest.cc中可以找到AssertHelper
类声明,包括赋值运算符,它返回void
:
void AssertHelper::operator=(const Message& message) const
所以现在澄清了编译器抱怨的原因.
3.但为什么导致这个问题并不清楚.尝试实现为什么ASSERT_THROW
和EXPECT_THROW
生成不同的代码.答案是来自文件include/gtest/internal/gtest-internal.h的宏
#define GTEST_FATAL_FAILURE_(message) \ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) #define GTEST_NONFATAL_FAILURE_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure)
其中包含return
致命案件.
4.但现在问题为什么这个断言通常运作良好?
要回答这个问题,请尝试调查在断言放入测试时以正确方式编写的代码剪切:
#includeclass my_exp {}; TEST (MyExp, ThrowMyExp) { ASSERT_THROW (throw my_exp (), my_exp); }
为了排除污染的答案我只是注意到在这种情况下return
声明ASSERT_THROW
也存在,但它被放在方法内:
void MyExp_ThrowMyExp_Test::TestBody ()
哪个回归void
!但是在你的例子中,断言放在main
返回的函数内部int
.看起来这是问题的根源!
尝试用简单的代码片段证明这一点:
void f1 () {}; void f2 () {return f1();}; //int f2 () {return f1();}; // error here! int main (int argc, char * argv []) { f2; return 0; }
5.所以最后的答案是:ASSERT_THROW
宏包含表达式的return语句,该语句计算结果void
以及何时将这样的表达式放入函数中,返回非空值,gcc抱怨错误.
PS但是无论如何我不知道为什么一个案例返回被使用但是对于其他情况不是.
更新:我在GitHub上问了这个问题并得到了以下答案:
ASSERT_XXX用作穷人的例外,允许它在禁用异常的环境中工作.它回报了; 代替. 它意味着在TEST()方法中使用,返回void.
更新:我刚刚意识到官方文档中描述的这个问题:
通过将它放在一个非void函数中,你会得到一个令人困惑的编译错误>比如"error:void value不应该被忽略,因为它应该是".