简体   繁体   中英

Constructor for a test class in Google Test

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

My questions is

1) When I run the test case CreateReaderAndGetTopic does the Constructor of InjectorTest gets called before executing the test case? Or should it be called explictly ?

2) Should my class InjectorTest have a constructor or should the code inside the constructor be moved to SetUpTestCase .

Let's mention first that the static class members SetUpTestCase and TearDownTestCase have been renamed respectively to SetUpTestSuite and TearDownTestSuite since googletest v1.8. See Beware of the nomenclature

They did that because the names SetUpTestCase and TearDownTestCase were grossly misleading. They suggest functions that will be run in every case of a test that is derived from the fixture class in which they are defined, which they weren't. SetUpTestCase was in fact run before the first of all tests derived from the fixture (and still is, if you have an older googletest installation), and TearDownTestCase was run after the last of all tests derived from the fixture.

As of googletest 1.8, all of the tests that derived from a fixture - which we'd naturally call its test cases - are collectively regarded as a test suite ; so the set-up function that runs before all of them is now called SetUpTestSuite and the tear-down function that runs after of them is called TearDownTestSuite . I will stick with the new improved names as I have the latest rev of googletest.

Look at this gtest code that demonstrates the calling order of a fixture's constructor and destructor, SetUp and TearDown , SetUpTestSuite and TearDownTestSuite :

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

You can get a useful peek under the hood if you just preprocess this file (and preferably, pipe through a pretty-printer) and look at what comes out:

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

In gtester.ii you'll be able to find:

...
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();
}
...

That is what the test case:

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

expands to after preprocessing. When googletest runs test case fixture.One :

  • It constructs a new instance of fixture_One_Test - which by inheritance, is a new instance of fixture .
  • The base fixture constructor is called.
  • The derived fixture_One_Test constructor is called. (But it's empty.)
  • Googletest calls fixture::Setup() through the fixture_One_Test instance.
  • It calls fixture_One_Test::TestBody() through the fixture_One_Test instance, which executes the payload of the test case.
  • It calls calls fixture::TearDown() through the fixture_One_Test instance.
  • It destroys the fixture_One_Test instance, which -
  • Calls the fixture_One_Test destructor, which simply -
  • Calls the fixture destructor.

Similarly for fixture_Two_Test and fixture_Three_Test .

And just before all of that, googletest calls fixture::SetupTestSuite , if it's is defined.

And just after all of that, googletest calls fixture::TearDownTestSuite , if it's is defined.

Now let's see that in action:

$ 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() and TearDownTestSuite() each run just once. The constructor, destructor, SetUp() and TearDown() each run 3 times = the number of test cases in the test suite.

So to your two questions:

When I run the test case CreateReaderAndGetTopic does the Constructor of InjectorTest gets called before executing the test case? Or should it be called explictly ?

The InjectorTest constructor is necessarily called to construct an instance of the class CreateReaderAndGetTopic_InjectorTest_Test , which Googletest does for you. It is called before SetUp() , which is called before TestBody() , which is the payload of the test case.

Should my class InjectorTest have a constructor...

InjectorTest will have a constructor, either by default or as defined by you; so you're wondering whether you should define one.

You should define one if you have something to do that needs to be done anew in preparation for each test case, and that had better be done before the SetUp() for each test case.

... or should the code inside the constructor be moved to SetUpTestCase?

The code you have inside the constructor:

m_reader = CreateReader();

should be moved out to SetUpTestCase - aka SetUpTestSuite - if it is something that does not need to be done anew in preparation for each test case but needs to be done once just before all test cases of InjectorTest .

As it stands, you cannot move that constructor code into SetUpTestSuite because it initializes a non-static class member of InjectorTest , m_reader . But do you in fact need or want a new XMLReader to be created by CreateReader() for each test case? Only you can decide.

If you do want to create a new reader for each test case, then you face the choice of creating it in the constructor or in SetUp() . Here you can be guided by the Googletest FAQ Should I use the constructor/destructor of the test fixture or SetUp()/TearDown()?

If you want to make sure your test cases in a fixture have the same setup, you should implement the SetUp and TearDown methods (notice the case)

Your InjectorTest fixture only gets constructed once, but the SetUp step (resp. the TearDown step) will be run before (resp. after) your test case is executed.

The constructor should only deal with things that should be only done once (if any), any behavior you want to enforce for your test cases should go in these 2 methods. In your example, if the m_reader member can be shared across all your test cases, you can initialize it in the constructor like you did.

To sumup, here is the sequence of operations that will be run:

  1. InjectorTest::InjectorTest() : test fixture is constructed
  2. For each test case:
    1. InjectorTest::SetUp() : setup for test case
    2. Test case is run (in your example InjectorTest::CreateReaderAndGetTopic )
    3. InjectorTest::TearDown() : setup is undone for next case
  3. InjectorTest::~InjectorTest() : destruction of the fixture object

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM