Some time ago, I posted an article about whether or not you should unit test an abstract class. It generated some[what] heated discussion in the comment section, which made me feel like in good old days when I just started writing on the blog :) Lots of debates in the comments, borderline name-calling. That was.. intense. Frankly, it sometimes hard to motivate myself to continue writing, but such arguments help reignite the spark.
Anyway, I wanted to write a small follow up to this blog post. To summarize its content, my main points was that you shouldn’t unit test abstract classes directly because they are a way for the production code to reuse some of the domain logic (and thus adhere to the DRY principle).
For tests, though, it shouldn’t matter whether the classes under test share the domain logic or duplicate it. Tests should view all production code as a black box, and approach verifying it with a blank slate. Otherwise, such tests will start couple to the code’s implementation details.
There are a couple of points I’d like to make here.
First, it could be that you write a library with an abstract class, and the whole point of that abstract class is to be used in the client’s code base. Such an abstract class may not even have derived classes in that library.
How to test it then?
In this case, emulate a typical consumer of your library: create a derived class yourself and test that class’s behavior. Still, no need to mock anything, that class is best written as a standalone class inside your test project.
Second, what if the base class is not abstract? What if it’s a concrete one?
Then, no issues with unit testing it directly. Again, only abstract classes are implementation details. That’s because you never deal with abstract classes at runtime, they are all abstractions (pun intended), and get converted into one of the derived concrete classes when you run the application. Hence, you should test the public API of those concrete classes.
But that’s not the case for base non-abstract classes. You can instantiate them directly and therefore they are not implementation details.
Finally, what if the abstract base class contains a method whose implementation is exactly the same for all of the derived concrete classes? Would I really unit test this method for each of the derived classes separately?
No, I wouldn’t.
I would unit test this method when testing one of the derived classes and omit when testing the others. That’s a bit of cheating of course, because this approach doesn’t view the class hierarchy as a black box anymore. But it’s a reasonable trade-off in my opinion. Just don’t forget to add the missing tests for the remaining derived class when their functionality starts to diverge.
Enjoy this message? Here are more things you might like:
Workshops — I offer a 2-day workshop for organizations on Domain-Driven Design and Unit Testing. Reply to this email to discuss.
Unit Testing Principles, Patterns and Practices — A book for people who already have some experience with unit testing and want to bring their skills to the next level.
Learn more »
My Pluralsight courses — The topics include Unit Testing, Domain-Driven Design, and more.
Learn more »