Make a Derived Class to Allow Testing an Abstract Class


In which I show how best to test an abstract class, which normally wouldn’t be instantiatable.

Abstract classes are not instantiatable, so how do you test one?

class Abstract
{
public:
	int common();
	virtual int special() = 0;
};

class Concrete : public Abstract
{
public:
	int special();
};

Say you want to test Abstract::common(), like so:

TEST(TestAbstract, helper_returns42)
{
	Abstract abs; //cannot declare variable ‘abs’ to be of abstract type ‘Abstract’
	ASSERT_EQ(42, abs.common());
}

It’s not possible, because common() special() is pure virtual (it has no implementation in Abstract). So how do you test a class that cannot be instantiated? It can be tempting to test through a concrete subclass:

TEST(TestAbstract, common_returns42)
{
	Concrete abs; 
	ASSERT_EQ(42, abs.common());
}

But this is generally a bad idea, since Concrete might change the behaviour of common(). Even though it is not virtual, it operates under a different state. And even though you know it will work now, you don’t know how Concrete will change in the future, and then you don’t want tests that don’t have anything to do with Concrete to start failing. Also, creating a Concrete object when you are testing on Abstract is confusing to the reader.

Instead, I recommend you derive a class to be used just for testing:


class AbstractForTest : public Abstract {
	int special();
};

TEST(TestAbstract, common_returns42)
{
	AbstractForTest abs; 
	ASSERT_EQ(42, abs.common());
}

In this way you get rid of the unwanted dependency, and the test is easier to understand. As a final note, make sure you name your test-class something that clearly distinguishes it as a testing artifact, like I did above. Also make sure to keep it in your test code (e.g. TestAbstract.cpp), not in your production code (e.g. Abstract.h/.cpp).

7 thoughts on “Make a Derived Class to Allow Testing an Abstract Class

  1. Hi Anders,

    When you say:

    because common() is pure virtual (it has no implementation in Abstract)

    I think you mean that “special” is pure virtual, correct?

    Actually, now that I think about it, maybe the pure virtual specifier (=0) in the class definition belongs with the “common” member function in the base class instead of the “special” member function, since the rest of the post uses “common” and not special.

    1. Hi Dan,

      You are absolutely, right, I meant that special() is pure virtual, not common(). Thanks!

      The pure virtual specifier does however belong where it is, on special(). The point is that I am trying to test a class that also has a pure virtual method, not the pure virtual method itself (which would be impossible, since it has no implementation). I have updated the post to make this more obvious.

  2. Hi Anders,

    Thanks for the clarification. Looking forward to reading additional posts when you have time.

Leave a comment