A Testing Pattern (TestingPatterns
) describing a way to reuse test cases for multiple implementations of an Interface.
- How to write a Test Suite against an Interface (or Abstract Class) that can be used to test all implementations of the interface.
- Write an AbstractTest for every Interface and Abstract Class). The AbstractTest should have an abstract FactoryMethod that creates an object with the type of the Interface.
- Write a ConcreteTest? for every implementation of the Interface. The ConcreteTest? should be a descendant of the AbstractTest and override the FactoryMethod to construct an instance of the implementation class.
is the test suite that really contains all of the actual tests, but it does not know how to construct instances of the testable objects (for that it uses the FactoryMethod
includes an implementation of the FactoryMethod
, and possibly a mechanism for running the test. It may also include tests that are specific to the implementation, but are not general to all implementors of the Interface.
My only lament for the AbstractTest is that Ant's "shell glob on class filename" method of finding the test suite will include your abstract base classes unless you've had the foresight to name them so it doesn't. I did patch my local copy to replace uninstantiable abstract tests with a placeholder ... I suppose I should offer it up for the world. -- MatthewAstley
currently uses this pattern to test various singletons. What I've done is set up the ant task to exclude
any test that begins with the word "Abstract." So Ant never runs the AbstractTest
but only the concrete tests.--AdewaleOshineye
We have side-stepped this problem a slightly different way... All AbstractTestCase?
do not follow the usual **/test/*Test naming pattern for tests (they're not really tests themselves after all), but the **/testing/*TestCase
pattern. Note that we also do not usally prefix them with Abstract, as the naming convention makes it obvious these are abstract classes. The advantages of this are two fold:
are not picked up with the usual **/test/*Test.class pattern used for <junit>
are easily packaged either in the main JAR, or an optional SDK jar, so that client of these interfaces or abstract classes can also leverage the abstract tests. (Normally, all our tests are not shipped: <jar excludes="**/test/**"/>.) The abstract tests thus become part of the deliverables of the project, next to their corresponding abstract classes/interfaces. --DominiqueDevienne
[Comments moved from SubclassToTest.]
How I Test Hierarchies
For unit testing class hierarchies, this is what I generally do. If I have an abstract class, I create an abstract TestCase
for that class. This TestCase
has methods for each member of the abstract class. Then for concrete classes, I extend the abstract TestCase
. This way I only need to add methods only when a method was added by the concrete subclasses. Because I only exercise the public interface
, I am unaffected by implementation details and put myself into the role of class client
. I always assume that if I have the need to access protected behavior then a user of my class will feel the same need. So, I always respond to this desire by refactoring the public interface instead of violating it.
's more detailed description of this pattern can be found at http://www.placebosoft.com/abstract-test.html
An example of refactoring AbstractTest
into place, for tests that mock WebService
s, appear here: http://broadcast.oreilly.com/2010/05/abstract-tests.html