Search code examples
c++unit-testingtestingpolymorphismgoogletest

Polymorphism for gtest type parameterized


I'm trying to use gtest type-parameterized to ensure the basic functionality of my classes. However I'm stucked in the test setup. Following is the example:

I have two classes called CatTest & DogTest, and a base class called AnimalTest that will test all the similarities of Cat & Dog:

template <typename T>
class AnimalTest : public ::testing::Test 
{
public:
    virtual void SetUp()
    {
      // Do something here so that it will call the correct setup
    }
};

TYPED_TEST_P( AnimalTest , HasLegs ) 
{
    ASSERT_EQ( 4, this->Legs );
}

REGISTER_TYPED_TEST_CASE_P( AnimalTest , HasLegs );

Now in my CatTest.cpp, I have the following macro declared ( same goes for DogTest )

typedef ::testing::Types< Cat > AnimalsTypes;

INSTANTIATE_TYPED_TEST_CASE_P( CatTest, AnimalTest , AnimalsTypes );

class CatTest : public CatSetUp
              , public AnimalTest< AnimalsTypes >
{
public:
    virtual void SetUp()
    {
        CatSetUp::SetUp();
    }
}

In a normal type-parameterized test example, HasLegs test will run for both Cat and Dog type. The problem here is CatTest has its own SetUp(), and so does DogTest(). These needs to be executed in order to initialize the Cat object so I can pass it to the type-parameterized test ( Animal test ). However these SetUp is never called, in fact even the constructor of DogTest() or CatTest() was never invoked. I thought that the type parameterized test will call the corresponding instance of the derived class with the overriden SetUp() ? Or am I missing something here ?


Solution

  • You shall not make a test class to be an object under test.

    I mean object-under-test should be member of your test class (aggregation, not inheritance) - then everything becomes simple:

    template <typename T>
    class AnimalTest : public ::testing::Test 
    {
    public:
        T objectUnderTest; // animal
        virtual void SetUp()
        {
           objectUnderTest.SetUp();
        }
    };
    
    TYPED_TEST_P( AnimalTest , HasLegs ) 
    {
        ASSERT_EQ( 4, objectUnderTest.Legs );
    }
    
    REGISTER_TYPED_TEST_CASE_P( AnimalTest , HasLegs );
    typedef ::testing::Types< Cat, Dog > AnimalsTypes;
    
    INSTANTIATE_TYPED_TEST_CASE_P( AnimalWithFourLegs, AnimalTest , AnimalsTypes );
    

    Explanation to

    However these SetUp is never called, in fact even the constructor of DogTest() or CatTest() was never invoked.

    is simple.

    First argument to INSTANTIATE_TYPED_TEST_CASE_P is not class name - it is just some name describing third argument - so you would know which test is which. Saying INSTANTIATE_TYPED_TEST_CASE_P( CatTest, AnimalTest , AnimalsTypes ); does not mean it is anyhow related to class CatTest... Read gtest-doc.