13

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

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

3 回答 3

14

如果您遇到“最令人头疼的解析”,解决方法通常是统一初始化:

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

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

于 2015-11-13T17:31:51.690 回答
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; \
    } \
...

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

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

MyClass(filename)

是模棱两可的,但根据最令人烦恼的解析规则,声明解释是首选,所以你最终得到:

MyClass filename

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

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

MyClass("some string")

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

MyClass "some string"
于 2014-12-28T21:17:56.563 回答
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)时,它首先求值 filename ,它产生一个立即丢弃的临时值,然后它求值MyClass(). 调用MyClass("filename")会导致预处理器实际将文字字符串复制到表达式中。解决此问题的一种方法是调用EXPECT_THROW((MyClass(filename)), std::runtime_error),即在语句周围使用一组括号。

于 2011-06-22T23:54:02.863 回答