Googletest不接受EXPECT_THROW中的临时对象

时间:2011-06-22 23:07:58

标签: c++ g++ googletest

我有一个没有默认构造函数的类,但构造函数可能会抛出。我想要进行类似的测试:

EXPECT_THROW(MyClass(param), std::runtime_error);

但编译器g++抱怨MyClass没有默认构造函数。但是,以下......

EXPECT_THROW(MyClass foo(param), std::runtime_error);

...有效,测试按预期通过。为什么Googletest不会接受临时对象?

class MyClass
{
public:
  MyClass(std::string const& filename);
  //...
};

有趣的是,我已经重构了我的测试,没有在单独的变量中使用文件名,当被要求检查时,我发现以下工作:

EXPECT_THROW(MyClass("somefilename"), std::runtime_error);

但以下情况并非如此:

std::string filename("somefilename");
EXPECT_THROW(MyClass(filename), std::runtime_error);

3 个答案:

答案 0 :(得分:10)

如果你被“最令人烦恼的解析”所打击,那么治愈通常是统一的初始化:

EXPECT_THROW(MyClass{param}, std::runtime_error);

(假设你的编译器理解C ++ 11)。

答案 1 :(得分:8)

在处理宏时,终极工具正在分析扩展的宏:

在你的情况下(和gtest 1.6):

EXPECT_THROW(MyClass(filename), std::runtime_error);

扩展为:

...
    bool gtest_caught_expected = false; \
    try { \
      if (::testing::internal::AlwaysTrue()) { MyClass(filename); }; \
    } \
    catch (std::runtime_error const&) { \
      gtest_caught_expected = true; \
    } \
    catch (...) { \
      gtest_msg.value = \
          "Expected: " "MyClass(filename)" " throws an exception of type " \
          "std::runtime_error" ".\n  Actual: it throws a different type."; \
      goto gtest_label_testthrow_88; \
    } \
    if (!gtest_caught_expected) { \
      gtest_msg.value = \
          "Expected: " "MyClass(filename)" " throws an exception of type " \
          "std::runtime_error" ".\n  Actual: it throws nothing."; \
      goto gtest_label_testthrow_88; \
    } \
...

正如您所看到的,EXPECT_THROW的参数不是对象,而是要在GTEST中进一步评估表达式,提供有效的try / catch块。

因此,您传递给它的任何内容都必须能够在当前范围的嵌套范围内作为表达式进行求值。在你的情况下:

MyClass(filename)

含糊不清,但根据最令人烦恼的解析规则,声明解释是首选,所以你最终得到:

MyClass filename

因此,您正在创建类MyClass的变量命名文件名 - 因此有关缺少构造函数的错误。

如果使用文字字符串,则不会触发此机制:

MyClass("some string")

以下将是无效的(并且没有歧义):

MyClass "some string"

答案 2 :(得分:2)

你能提供更多信息吗?我构造了一个示例,该示例适用于只有一个参数构造函数的类。

#include <iostream>
#include <stdexcept>

#include "gtest/gtest.h"

class m {
    public:
        m(std::string a) {std::cout << "one argument constructor" << std::endl;}
};

int main() {
    EXPECT_THROW(m("hat"), std::runtime_error);
}

输出:

one argument constructor
gtt.cc:12: Failure
Expected: m("hat") throws an exception of type std::runtime_error.
Actual: it throws nothing.

修改 我并不认为自己是C / C ++预处理器神秘内部工作的专家,但我认为这与评估表达式时遵循的规则有关,特别是在预处理器领域,括号是王道。当预处理器评估MyClass(filename)时,它首先评估产生临时值的文件名,该文件立即被丢弃,然后评估MyClass()。调用MyClass("filename")会导致预处理器将文字字符串实际复制到表达式中。解决此问题的一种方法是调用EXPECT_THROW((MyClass(filename)), std::runtime_error),即在语句周围使用一组括号括起来。