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

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 の filename という名前の変数を作成しているため、コンストラクターが見つからないというエラーが発生します。

リテラル文字列を使用する場合、このメカニズムはトリガーされません。

MyClass("some string")

以下は無効になるためです(そしてあいまいさはありません):

MyClass "some string"
于 2014-12-28T21:17:56.563 に答える
2

もっと情報を教えてもらえますか?引数コンストラクターが1つしかないクラスで正常に機能する例を作成しました。

#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")と、プリプロセッサは実際にリテラル文字列を式にコピーします。この問題を回避する1つの方法は、を呼び出すことですEXPECT_THROW((MyClass(filename)), std::runtime_error)。つまり、ステートメントを囲む括弧のセットを使用します。

于 2011-06-22T23:54:02.863 に答える