ASSERT_THROW: error: void value not ignored as it ought to be

ASSERT_THROW: error: void value not ignored as it ought to be

我是 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;
}

编译输出:

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); 
    ^

短版

你写测试的方式不对,写测试you should把断言放在测试(宏TEST)或测试夹具(宏TEST_F)中。

长版

1。到底发生了什么?

要找出真正的问题并不容易,因为 Google 测试框架使用隐藏真实代码的宏。要查看宏替换后的代码需要进行预处理,类似这样:

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。 OK,不同行为的原因找到了,让我们继续。

在文件 src/gtest.cc 中可以找到 AssertHelper class 声明包括赋值运算符 which return void:

void AssertHelper::operator=(const Message& message) const

所以现在编译器抱怨的原因已经澄清了。

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)

其中包含 return 致命案例。

4。但现在的问题是为什么这个断言通常效果很好?

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

#include <gtest/gtest.h>

class my_exp {};

TEST (MyExp, ThrowMyExp)
{
    ASSERT_THROW (throw my_exp (), my_exp);
}

为了排除答案的污染,我只注意到在这种情况下,ASSERT_THROWreturn 语句也存在,但它放在方法中:

void MyExp_ThrowMyExp_Test::TestBody ()

哪个returnvoid!但是在您的示例中,断言位于 main 函数中,其中 return 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 并且当这样的表达式被放入 return 非 void 值的函数时,gcc 会抱怨关于错误。

P.S。但无论如何我不知道为什么在一种情况下使用 return 而在另一种情况下不使用

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

ASSERT_XXX is used as a poor man's exception to allow it to work in environments where exceptions are disabled. It does a return; instead. It is meant to be used from within the TEST() methods, which return void.

更新:我刚刚意识到 the official documentation:

中描述的这个问题

By placing it in a non-void function you'll get a confusing compile error > like "error: void value not ignored as it ought to be".