ASSERT_THROW:错误:无法忽略void值,因为它应该是

har*_*j90 2 googletest

我是gtest的初学者.我试图使用ASSERT_THROW将编译失败.任何人都可以帮助这个:

class my_exp {};

int main(int argc, char *argv[])
{
   EXPECT_THROW(throw my_exp(), my_exp); // this will pass
   // This will through below compilation error 
   ASSERT_THROW(throw my_exp(), my_exp); 
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译输出:

ERROR : 
In file included from /usr/include/gtest/gtest.h:57:0,
             from gtest.cpp:1:
gtest.cpp: In function ‘int main(int, char**)’:
gtest.cpp:12:3: error: void value not ignored as it ought to be
    ASSERT_THROW(throw my_exp(), my_exp); 
    ^
Run Code Online (Sandbox Code Playgroud)

Glu*_*ton 7

精简版

你以错误的方式编写测试,编写测试你应该把断言放在测试(宏TEST)或测试夹具(宏TEST_F)中.

长版

1.真的发生了什么?

要找出真正的问题并不容易,因为Google Testing Framework使用隐藏真实代码的宏.要在宏替换后查看代码以执行预处理,如下所示:

g++ -E main.cpp -o main.p
Run Code Online (Sandbox Code Playgroud)

使用时预处理的结果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;
}
Run Code Online (Sandbox Code Playgroud)

对于EXPECT_THROW结果将是,除了一些区别一样:

    else
        gtest_label_testthrow_7:
        ::testing::internal::AssertHelper (::testing::TestPartResult::kNonFatalFailure, "main.cpp", 7, gtest_msg.value) = ::testing::Message ();
Run Code Online (Sandbox Code Playgroud)

2.好的,找到了不同行为的原因,让我们继续.

在文件src/gtest.cc中可以找到AssertHelper类声明,包括赋值运算符,它返回void:

void AssertHelper::operator=(const Message& message) const
Run Code Online (Sandbox Code Playgroud)

所以现在澄清了编译器抱怨的原因.

3.但为什么导致这个问题并不清楚.尝试实现为什么ASSERT_THROWEXPECT_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)
Run Code Online (Sandbox Code Playgroud)

其中包含return致命案件.

4.但现在问题为什么这个断言通常运作良好?

要回答这个问题,请尝试调查在断言放入测试时以正确方式编写的代码剪切:

#include <gtest/gtest.h>

class my_exp {};

TEST (MyExp, ThrowMyExp)
{
    ASSERT_THROW (throw my_exp (), my_exp);
}
Run Code Online (Sandbox Code Playgroud)

为了排除污染的答案我只是注意到在这种情况下return声明ASSERT_THROW也存在,但它被放在方法内:

void MyExp_ThrowMyExp_Test::TestBody ()
Run Code Online (Sandbox Code Playgroud)

哪个回归void!但是在你的例子中,断言放在main返回的函数内部int.看起来这是问题的根源!

尝试用简单的代码片段证明这一点:

void f1 () {};
void f2 () {return f1();};
//int  f2 () {return f1();}; // error here!

int main (int argc, char * argv [])
{
    f2;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

5.所以最后的答案是:ASSERT_THROW宏包含表达式的return语句,该语句计算结果void以及何时将这样的表达式放入函数中,返回非空值,gcc抱怨错误.

PS但是无论如何我不知道为什么一个案例返回被使用但是对于其他情况不是.

更新:我在GitHub上问了这个问题并得到了以下答案:

ASSERT_XXX用作穷人的例外,允许它在禁用异常的环境中工作.它回报了; 代替. 它意味着在TEST()方法中使用,返回void.

更新:我刚刚意识到官方文档中描述的这个问题:

通过将它放在一个非void函数中,你会得到一个令人困惑的编译错误>比如"error:void value不应该被忽略,因为它应该是".

  • 回答您的 PS 问题:致命断言中止测试执行,而非致命断言不会。因此,前者包含一个 `return` 语句,因此如果致命断言失败,则不会再运行测试中的代码。 (2认同)