Data Layer Testing: Test Inheritance Patterns
I'm preparing for my tutorial on Database and Data Layer unit testing that I will be giving at the Agile Practices Conference next week. It's always nice to have a full 3 hours to get pretty deep into something. 75 minutes just isn't enough to grasp a concept deeply enough, just to graze it around the edges.
When writing data layer tests, there are several patterns I've noticed, especially around the notion of inheritance within the test classes (Abstract test class pattern). I've observed at least three different patterns emerging from inheritance that I've personally used, all relating to data layer testing, but could be used elsewhere:
Abstract Utility Class
This class will usually be a base class for tests written for data layer objects. it would contain "facilities" such as database helper classes, setup and teardown methods that would automatically rollback any test and anything else a derived base class that was testing a data layer object would need (helper methods for asserting complex stuff, for example).
This is a classic "Abstract test class" pattern, and the next two are built on top of it.
Template Test Class
The template test class will contain abstract methods as unit tests, which any derived class would have to override and perform. That means that if you are always testing the same things against a data layer object (insert returns different IDs, update works etc...) test authors on new data layer classes who derive from this class will never forget to implement at least these basic tests.
they would also get the facilities for doing assertions and other things from the base class, as depicted in the previous pattern. makes sure you don't forget tests, saves some time on the infrastructure.
Abstract Driver Test Class
This class will have non abstract test case methods inside it that will always run the same way. these test methods will call (using abstract methods) to the derived class' implementation of type specific actions (insert specific for a category, or update specific to person) .
That leaves the derived class to only implement very basic things such as insert (and return the ID), update, or delete (by ID). the test methods in the base class will do the rest of the work. derived classes don't need to implement any tests unless they want to add type specific tests which don't belong on the base class.
in the image to the left the green methods are tests that the base class runs, and the yellow ones are type specific helpers that the derived class has to implement.
this makes writing tests for a new data layer object (as long as its interface is the same) very simple by inheriting a test class and implementing a few methods. all the test permutations in the base class will then run on the data layer object. saves lots of time and forgetting tests.
What patterns have you come across?