Inspired by the Gerard Meszaros book
xUnit Test Patterns: Refactoring Test Code
, I have written down a pattern, which I used already many times:
Own Library Interface
Also known as: 'Skin and Wrap the API' [
Working Effectively with Legacy Code
by Michael Feathers]
How can we make a code testable, when the code depends on a library class, which can't be replaced by a 'Test Double'?
We write our own interface that exactly mirrors the API of the library class. In our system under test (SUT) we use the interface instead of the library class itself.
Some library classes do not inherit from an interface, they do not declare their methods as virtual or they provide static methods, so it is not possible to introduce a
Test Double to the SUT via
Dependency Injection or
Dependency Lookup to replace the library class during testing. This problem arises very often when we need to use system or third party libraries (like the .NET framework) where we can’t modify the library classes and have to use them as they are.
Library designers prefer to use class-based APIs instead of interfaces, because they can be evolved in later versions of the library. If they want to add members to a library interface in a later version , they would break existing code [
Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries
by Abrams and Cwalina].
Very often the SUT can’t be tested together with the library class, because the library class can’t be used in the test environment. The reason may be that the library class will not return values needed for the test or executing it would have undesirable side effects.
How it Works
We write our own interface which mirrors the API of a library class we are using in our SUT. Our own interface does not need to contain the complete API of the library class but may contain only the subset we are requiring for our SUT.
We implement a thin wrapper for the library class which inherits from our own interface. The wrapper will contain no logic. Each method can simply be forwarded to the library class, because the signatures of our own interface are the same as the library class.
The SUT must use the interface instead of the library class itself. The SUT will be initialized with a concrete object via
Dependency Injection or
Dependency Lookup. In the production environment the thin wrapper is used. In the test environment we can replace the thin wrapper with a
Test Double.
When to Use It
We have to use the
Own Library Interface when we use a third party library class in our SUT which has both of the two following characteristics:
- The dependency on the library class prevents us from executing the SUT in a test environment. It may be plain impossible, too slow, too complex or too expensive to prepare a test environment for testing the SUT together with the library class.
- The library class can not be replaced by a Test Double, because it does not inherit from an interface, it does not declare its methods as virtual or it has static methods.
These circumstances very often lead to the smell
Developers Not Writing Tests. The SUT will be declared as untestable. Also TDD beginners often stumble over this problem and get the impression that TDD is not applicable to real world examples.
Implementation Notes
Library classes which define the API for operating system mechanisms (registry, event log, services), the API for hardware sub systems (network infrastructure) or the API to other software components (SMTP server, POP3 server) are candidates for the usage of the
Own Library Interface pattern. Preparing a fixture for testing own classes which are using such library classes may be plain impossible, too slow, too complex or too expensive. See
TDD for Beginners as an detailed example for the usage of the
Own Library Interface pattern.
We do not need to use the
Own Library Interface pattern, when we can test our SUT together with the library class. For example the
File or
Directory classes from the .NET framework can easily be tested together with the SUT, because preparing files and directories during test setup as well as checking them after exercising the SUT is quite easy.
No comments:
Post a Comment