C++ – Testing Abstract Class Behavior

abstract classcinheritancetdd

I'm currently refactoring an existing design, which was created without TDD. There is a class hierarchy with one abstract base class and two subclasses. In the original design, these classes were mostly just data holders without much behavior. I have identified some functionality which should be implemented in the base class, and I'd like to write tests for this functionality now. But since the class is abstract, I cannot instantiate it (obviously).

Note: The functionality I'd like to test doesn't invoke any pure virtual methods.

class Base {}; // Is abstract

TEST(BaseTest, doesSomethingAmazing) {
    Base aBase; // <-------- Not possible!!! 
    ASSERT_THAT(aBase.amazeMe(), Eq(AMAZING_RESULT));
}

Edit: To clarify a few things:

  • Inheritance does actually make sense in this situation – both subclasses map to specific domain concepts, and polymorphism helps keep the surrounding code clean
  • There is behavior which will be used in both subclasses, and which needs data that is common to both classes. So I think it makes sense to put it in a common super class.

I can think of several possible solutions, but none of them seems optimal to me:

  • Add a subclass to the test code, which implements all pure virtual functions. Downside: Hard to name that subclass in a concise way, understanding the tests becomes harder
  • Instantiate an object of the subclass instead. Downside: Makes the tests pretty confusing
  • Add empty implementations to the base class. Downside: Class is not abstract anymore

I tend towards option 3, to make the tests as clear as possible, but I'm not really satisfied with that. Is there a better way I'm not aware of?

Best Answer

As long as the functionality you'd like to test doesn't invoke any pure virtual methods and isn't overridden in subclasses, I'd stick with your bullet point number 1 - creating a test-specific subclass. You could name it Sub<ClassName> or any generic name reflecting that the subclass itself is not important.

Now if what you want to test can be altered in any way by the final concrete class, you might want to consider this :

I don't know if there's an equivalent in the C++ test framework you're using, but NUnit (and I believe JUnit) let you implement the Abstract Test pattern.

In short, you have

  • An abstract base test class. It contains a abstract factory method used to generate the object under test, and the test methods per se. These methods verify things that must stay true regardless of the concrete object underneath.

  • As many derived test classes as there are derivatives of the abstract class under test. You just have to implement the factory method here to return an instance of the derived class.

When the test runner sees a derived test class, it will automatically execute all test methods inherited from the base test class against the factory method-generated object.