You have a set of classes to write. Classes that have details specific to each, but that also have a lot in common.
You don’t like to repeat yourself and like your code DRY.
So you have created a base class to contain all the common code.
Everything is going along swimmingly. But then you hit a snag.
One or two methods are needed that would have no implementation in the base class. Instead of adding methods on the base that have no implementation, you decide to mark them
abstract. Much neater and this way the code conveys that it is the responsibility of a descendant to provide the behavior of these methods (instead of relying on non-existent behavior in the base).
Marking one or more methods
abstract, however, means all your tests on the base class now fail because you can’t instantiate an abstract class…
You really don’t want to give up on this class being abstract, and you really do want to test the default behavior this class provides.
Not to worry.
If the goal is to test the abstract base class, but you can only instantiate descendants, then the answer is simple:
Define a descendant specifically intended to test the base class.
There is nothing anywhere that says you can only create descendants that will be used in production code.
There also is nothing anywhere that says that you are obliged to instantiate the exact class under test in your tests for a class.
In fact using a descendant class of the class under test is often a good way to break dependencies and provide “stubs” for methods called by the method under test.
In short, all you need to do is
- Define a descendant specifically to test the base class.
- Override the abstract methods of the base class and give them an implementation that supports your test.
- Add helper methods so you can direct it to respond as required by your tests.
- Instantiate this test descendant, but assign the instance to a variable of the base class type. This ensures that your tests can’t ever use the helper methods without using a cast.
- Only use a cast to the type of the test descendant in the “arrange” part of your tests and only to call your custom helper methods.