Unit testing a class A that derives from an abstract class B

117 views Asked by At

I am required to unit test a class B that derives from an abstract class A, which has some implementations.

My question is: Should you unit test the parent type (e.g. the abstract ClassB) or the sub-class / derived type (e.g. ClassA)

2

There are 2 answers

1
Pressacco On BEST ANSWER

Unit tests are written, in part, to maintain code integrity. In keeping with the Pareto principle (80/20 rule), the implementation details that you want to test are generally in the derived type. So...

Scenarios

Typical Scenario

Unit tests should be written for the derived type / sub-class, but the unit test implementation should reference the parent type as per the SOLID Liskov substitution principle:

“objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program"

In other words, you are testing Dog, but the unit test source code will refer to Mammal:

Mammal pet = new Dog();
pet.Speak();

Atypical Scenario

If the base type (e.g. Mammal) contains executable code that you want to unit test, then you will have to create an instance of a derived type (e.g. Dog). For example, you could do something like this:

[TestCase]
public class MammalTest
{
    [TestMethod]
    AbstractMethodNameHere_YourTestCase_YourExpectedResults()
    {
       Mammal pet = new Dog();

       // Here you could test the method that has been implemented 
       // in the base class.
       Assert.IsTrue(pet.AbstractMethodNameHere());
    }
}

To re-iterate, you typically would not write tests that are specific to the base class as the implementation details are generally in the derived type.

Additional Reading

0
prgmtc On

In general, you should only test through the public API of your objects. In this case, that would mean testing the concrete subclasses themselves, the abstract superclass is an implementation detail.

If you feel this causes unnecessary duplication and/or you are developing some sort of framework and provide the abstract base class (or more general an interface) as an extension point, you might look into the concept of contract tests. A summary of contract tests: write tests against the public API (the interface or the abstract base class) describing all the invariants that should hold for all implementations of this interface. Then run these tests on concrete implementations of this interface.

I would only recommend contract tests if the abstract class/interface is a publicly exposed API however. The "if I test each concrete implementation seperately I'm duplicating a lot of tests"-smell can be mitigated in better ways, e.g. by replacing the inheritance relation with object composition.