Google Test中测试类的构造函数

问题描述 投票:1回答:2
namespace {

using namespace std;
// Declare the google test case
class InjectorTest : public ::testing::Test {

std::shared_ptr<MyData>> m_reader;
public:
    static void SetUpTestCase() {

    }
    static void TearDownTestCase() {

    }

    InjectorTest()
    {
        //Create Reader code here !!!!
        m_reader = CreateReader();

    }
    std::shared_ptr<DDSTopicReader<MyData>> getXMLReader() {

        return m_reader;
    }
};

TEST_F(InjectorTest, CreateReaderAndGetTopic) {
        auto reader = getXMLReader();
        std::string topic_name = reader->getTopicName();
        EXPECT_EQ(topic_name, "test_topic");
}
}; // anonymous namespace

我的问题是

1)当我运行测试用例CreateReaderAndGetTopic时,在执行测试用例之前是否会调用InjectorTest的Constructor?或者它应该被明确地称为?

2)我的班级InjectorTest应该有一个构造函数,还是应该将构造函数中的代码移动到SetUpTestCase

c++ googletest
2个回答
1
投票

如果你想确保你的测试用例具有相同的设置,你应该实现SetUpTearDown方法(注意案例)

你的InjectorTest夹具只能构造一次,但是SetUp步骤(分别是TearDown步骤)将在你的测试用例执行之前(相反)执行。

构造函数应该只处理应该只执行一次的事情(如果有的话),你想要为你的测试用例强制执行的任何行为都应该放在这两种方法中。在您的示例中,如果可以在所有测试用例中共享m_reader成员,则可以像在构建器中一样初始化它。

总结一下,这是将要运行的操作序列:

  1. InjectorTest::InjectorTest():构建测试夹具
  2. 对于每个测试用例: InjectorTest::SetUp():设置测试用例 测试用例运行(在你的例子中InjectorTest::CreateReaderAndGetTopicInjectorTest::TearDown():下一个案例的设置已撤消
  3. InjectorTest::~InjectorTest():破坏夹具对象

0
投票

让我们首先提一下,自googletest v1.8以来,静态类成员SetUpTestCaseTearDownTestCase已经分别重命名为SetUpTestSuite and TearDownTestSuite。见Beware of the nomenclature

他们这样做是因为名字SetUpTestCaseTearDownTestCase极具误导性。它们建议在每个测试的情况下运行的函数,这些函数是从定义它们的fixture类派生的,而它们不是。 SetUpTestCase实际上是在从灯具得到的所有测试中的第一个之前运行的(并且仍然是,如果你有一个较旧的googletest安装),并且TearDownTestCase是在从灯具派生的所有测试的最后一个之后运行的。

从googletest 1.8开始,所有来自灯具的测试 - 我们自然称之为测试用例 - 被统称为测试套件;所以在所有这些之前运行的设置函数现在称为SetUpTestSuite,并且在它们之后运行的拆卸函数称为TearDownTestSuite。我将坚持使用新的改进名称,因为我有googletest的最新版本。

看看这个gtest代码,演示了fixture的构造函数和析构函数,SetUpTearDownSetUpTestSuiteTearDownTestSuite的调用顺序:

gtester.cpp

#include <gtest/gtest.h>
#include <iostream>

struct fixture : ::testing::Test
{
    fixture() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    ~fixture() override {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    void SetUp() override {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    void TearDown() override {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    static void SetUpTestSuite() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    static void TearDownTestSuite() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

TEST_F(fixture, One) {
    ASSERT_EQ(1,1);
}

TEST_F(fixture, Two) {
    ASSERT_NE(1,0);
}

TEST_F(fixture, Three) {
    ASSERT_LT(1,2);
}

如果你只是对这个文件进行预处理(最好是通过一台漂亮的打印机管道),看看会发生什么,你可以在幕后得到一个有用的窥视:

$   g++ -E -P gtester.cpp | clang-format > gtester.ii

gtester.ii,你将能够找到:

...
class fixture_One_Test : public fixture {
public:
  fixture_One_Test() {}
private:
  virtual void TestBody();
  static ::testing::TestInfo *const test_info_ __attribute__((unused));
  fixture_One_Test(fixture_One_Test const &) = delete;
  void operator=(fixture_One_Test const &) = delete;
};
::testing::TestInfo *const fixture_One_Test::test_info_ =
    ::testing::internal::MakeAndRegisterTestInfo(
        "fixture", "One", nullptr, nullptr,
        ::testing::internal::CodeLocation("gtester.cpp", 31),
        (::testing::internal::GetTypeId<fixture>()),
        ::testing::internal::SuiteApiResolver<fixture>::GetSetUpCaseOrSuite(),
        ::testing::internal::SuiteApiResolver<
            fixture>::GetTearDownCaseOrSuite(),
        new ::testing::internal::TestFactoryImpl<fixture_One_Test>);
void fixture_One_Test::TestBody() {
  switch (0)
  case 0:
  default:
    if (const ::testing::AssertionResult gtest_ar =
            (::testing::internal::EqHelper<
                decltype(::testing::internal::IsNullLiteralHelper(
                    1, ::testing::internal::TypeIsValidNullptrConstant<decltype(
                           1)>()))::value>::Compare("1", "1", 1, 1)))
      ;
    else
      return ::testing::internal::AssertHelper(
                 ::testing::TestPartResult::kFatalFailure, "gtester.cpp", 32,
                 gtest_ar.failure_message()) = ::testing::Message();
}
...

这就是测试用例:

TEST_F(fixture, One) {
    ASSERT_EQ(1,1);
}

在预处理之后扩展到。当googletest运行测试用例fixture.One时:

  • 它构造了一个fixture_One_Test的新实例 - 通过继承,它是fixture的一个新实例。
  • 调用基础fixture构造函数。
  • 调用派生的fixture_One_Test构造函数。 (但它是空的。)
  • Googletest通过fixture::Setup()实例调用fixture_One_Test
  • 它通过fixture_One_Test::TestBody()实例调用fixture_One_Test,该实例执行测试用例的有效负载。
  • 它通过fixture::TearDown()实例调用fixture_One_Test
  • 它摧毁了fixture_One_Test实例,其中 -
  • 调用fixture_One_Test析构函数,简单地说 -
  • 调用fixture析构函数。

同样对于fixture_Two_Testfixture_Three_Test

就在所有这些之前,googletest调用fixture::SetupTestSuite,如果已定义的话。

就在所有这些之后,googletest会调用fixture::TearDownTestSuite,如果已定义的话。

现在让我们看看它在行动:

$ g++ -Wall -Wextra -o gtester gtester.cpp -lgtest_main -lgtest -pthread
$ ./gtester 
Running main() from /home/imk/Downloads/googletest-master/googletest/src/gtest_main.cc
[==========] Running 3 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 3 tests from fixture
static void fixture::SetUpTestSuite()
[ RUN      ] fixture.One
fixture::fixture()
virtual void fixture::SetUp()
virtual void fixture::TearDown()
virtual fixture::~fixture()
[       OK ] fixture.One (0 ms)
[ RUN      ] fixture.Two
fixture::fixture()
virtual void fixture::SetUp()
virtual void fixture::TearDown()
virtual fixture::~fixture()
[       OK ] fixture.Two (0 ms)
[ RUN      ] fixture.Three
fixture::fixture()
virtual void fixture::SetUp()
virtual void fixture::TearDown()
virtual fixture::~fixture()
[       OK ] fixture.Three (0 ms)
static void fixture::TearDownTestSuite()
[----------] 3 tests from fixture (0 ms total)

[----------] Global test environment tear-down
[==========] 3 tests from 1 test case ran. (0 ms total)
[  PASSED  ] 3 tests.

SetUpTestSuite()TearDownTestSuite()每次只运行一次。构造函数,析构函数,SetUp()TearDown()每次运行3次=测试套件中的测试用例数。

那么对你的两个问题:

当我运行测试用例CreateReaderAndGetTopic时,在执行测试用例之前是否会调用InjectorTest的构造函数?或者它应该被明确地称为?

必须调用InjectorTest构造函数来构造类CreateReaderAndGetTopic_InjectorTest_Test的实例,Googletest会为您执行此操作。它在SetUp()之前调用,在TestBody()之前调用,这是测试用例的有效负载。

我的InjectorTest类应该有一个构造函数......

InjectorTest将有一个构造函数,默认或由您定义;所以你想知道是否应该定义一个。

你应该定义一个,如果你有事情需要重新完成,为每个测试用例做准备,最好在每个测试用例的SetUp()之前完成。

...或者构造函数中的代码是否应该移动到SetUpTestCase?

你在构造函数中的代码:

m_reader = CreateReader();

应该转移到SetUpTestCase - a.k.a SetUpTestSuite - 如果它不需要重新准备每个测试用例,但需要在InjectorTest的所有测试用例之前完成一次。

就目前而言,您无法将该构造函数代码移动到SetUpTestSuite中,因为它初始化了InjectorTestm_reader的非静态类成员。但实际上你是否需要或希望XMLReader为每个测试用例创建一个新的CreateReader()?只有你可以决定。

如果您确实想为每个测试用例创建一个新的阅读器,那么您可以选择在构造函数或SetUp()中创建它。在这里,您可以通过Googletest常见问题解答Should I use the constructor/destructor of the test fixture or SetUp()/TearDown()?进行指导

© www.soinside.com 2019 - 2024. All rights reserved.