Our next blog is going to be the first in a series of blogs that focus on testing the design patterns, and what we can learn about TDD and design from these investigations. However, the discussion does require that you understand the pattern before we begin.
So, if you are not completely comfortable with the Chain of Responsibility, it would be a very good idea for you to read up on the pattern while we are creating the blog posting.
Here is a link to our pattern repository page on the CoR. Please take a few minutes to read it through and post any questions you have here in our comments section.
The Chain of Responsibility
Thursday, June 28, 2012
Friday, June 15, 2012
Mock Objects, Part 3
Dependency Injection
Imagine that the example use previously was implemented differently:
public class BoundaryAlarm {
private GPS myGPS;
private DashLight myDashLight;
public BoundaryAlarm(){
myGPS = new GPSImpl();
myDashLight = new DashLightImpl();
}
public void CheckFieldLocation(){
// Implementation unchanged
}
}
The difference is that the implementations of the GPS and DashLight
dependencies (namely GPSImpl and
DashLightImpl) are created in
the constructor of BoundaryAlarm
directly. No matter what technique we
use to create mock implementations of these dependencies, it does not matter
because the mocks will never be used.
Remember, we are forced to test everything which is in
scope but which is not under the control of the test. If we write tests for BoundaryAlarm in its current state, we will also be
testing the objects (and the hardware) it depends upon. We will have a test that can fail for many
different reasons, and thus when it fails we will have to investigate to find
out which of those reasons is the culprit.
This will waste our time and will drastically reduce the value of the
testing effort.
We need, somehow, to inject
the dependencies into the class we’re testing, so that at test time we can
inject the mocks instead, putting the test in control of the dependencies
(leaving only BoundaryAlarm’s
implementation as the thing being tested).
Let’s note that the example above really contains a bad bit
of design. The BoundaryAlarm class is really two different things: it is
the consumer (Client) of the GPS
and DashLight services, and the
creator of them as well. Any given
entity in a system should have one of these relationships, not both: the client
of a service couples to the way the service is used, but not necessarily its
concrete type, whereas the creator of an object always couples to its concrete
type. Here we feel the pain of this bad
design decision in the difficultly we’re having in trying to test just what we
wish to specify, and no more.
Here again this is a question of technique, and here again
we could probably come up with any number of ways of solving this problem. We need to know more than one way because the
context of our problems will be different at times, and a given technique that
worked will in one situation may be totally inappropriate in another. We’ll look at four different ones here.
1.
Direct Injection
This is basically what we did initially; we allowed the
dependency to be handed in via the constructor (and, btw, from this point
forward we’ll just use a single dependency for brevity -- GPS).
We could, alternately, have provided a setter:
public class BoundaryAlarm {
private GPS myGPS;
public BoundaryAlarm(){
myGPS = new GPSImpl();
}
public void
setGPS(GPS aGPS) {
myGPS = aGPS;
}
public void CheckFieldLocation(){
// Implementation unchanged
}
}
This makes it possible for the test to inject the mock, but
note that the setter does not remove the new
GPSImpl() offending code from the BoundaryAlarm. If we go completely back to the previous
approach:
public class BoundaryAlarm {
private GPS myGPS;
public BoundaryAlarm(GPS aGPS){
myGPS = aGPS;
}
public void CheckFieldLocation(){
// Implementation unchanged
}
}
Then
BoundaryAlarm is a
client of the GPS service,
but is not also the creator of it. The
problem, of course, is that any entity (not just the test) can hand in any
implementation of the GPS service,
and this could represent a security problem in some domains. Some unscrupulous individual could create an
implementation that did something unwanted or illegal, and we’ve left ourselves
open. It’s hard to imaging such an
implementation of a GPS unit, so
here direct injection might be just fine… but imagine a banking application
with dependencies on a funds transfer subsystem, and the possibilities become
alarming.
So,
another way to go is to use a design pattern: Service Locator
2.
The Service Locator Pattern
The
service locator approach basically says that it’s better not to have a client
object create its own service object(s), but rather to delegate this creation
to a factory or registry object. The
implementation of such a factory could vary widely based on the nature of the
service object(s) being created, whether there is variation in their types or
construction, whether there are multiple clients with different application contexts,
etc…
In
our case, there is only one client and only one service version, and so we’d
implement the locator simply:
public class BoundaryAlarm {
private GPS myGPS;
public BoundaryAlarm(){
myGPS = GPSLocator.Getinstance().GetGPS();
}
public void CheckFieldLocation(){
// Implementation unchanged
}
}
class GPSLocator {
private static GPSLocator _instance = new GPSLocator();
private GPS theGPS;
private GPSLocator(){
theGPS = new GPS();
}
public static GPSLocator Getinstance() {
return _instance;
}
public GPS GetGPS() {
return theGPS;
}
// For testing
public void setGPS(GPS aGPS) {
theGPS = aGPS;
}
public void resetGPS() {
theGPS = new GPS();
}
}
Note
that the service locator () is a singleton [1].
This is important because we need to ensure that the instance of the
locator being used is the same one that the test will interact with. Also note the “for testing” methods that
allow the test to change the implementation that the locator returns to
something beneficial for testing (a mock, in this case) and then reset the
locator to work in its normal way when the test concludes.
Of
course, this could represent a similar security threat as with direct
dependency injection, and so most likely these additional methods would be
removed when the code was shipped. The
advantage here is that client objects tend to grow in number whereas locators
and other forms of factory objects are much less likely to do so, and so we’ve
reduced the amount of maintenance we have to do.
3 – Dependency Injection Frameworks
As with the creation of mocks, injecting them can also be
done with automation. A dependency
injection framework (or DIF) can essentially provide a service locator for you.
There are many different tools for doing this, and as we do
not want to focus overmuch on tools (TDD is not about tools per se) we will
simply give a single example. We are not
advocating for this particular tool, it’s just one we’ve seen used fairly
frequently. It is called Structure Map
[2], and it happens to be a .Net tool.
There are plenty of such tools for Java and other languages/frameworks.
First, we change the BoundaryAlarm
code:
public class BoundaryAlarm {
private GPS myGPS;
public BoundaryAlarm(){
myGPS = ObjectFactory.GetInstance<GPS>();
}
public void CheckFieldLocation(){
// Implementation unchanged
}
}
ObjectFactory is a class that is provided by Structure
Map. For it to work, we need to bind to
a resource that will map a type referenced to a real type. Structure Map can actually map to many
different kinds of resources, but we’ll choose XML here as it makes for an
easy-to-understand example.
// In
StructureMap.config
<StructureMap>
<DefaultInstance
PluginType="GPS"
PluggedType="GPSImpl"
ConnectionString="...." />
</StructureMap>
All this does in ensure that every time the type “GPS” is specified, ObjectFactory will return an instance
of GPSImpl. Now, in the test we do this:
[TestMethod]
public void
testBoundaryAlarm() {
GPSMock mock = new GPSMock();
ObjectFactory.InjectStub(typeof(GPS), mock);
BoundaryAlarm testAlarm = new
BoundaryAlarm();
//The body of the test, then
ObjectFactory.ResetDefault();
}
Again, this is just an example using this particular tool. The advantage here over writing your own
service locators is that these tools typically have a way of disabling the
injection (disabling the InjectStub() method in
this case) before the code is shipped, which further reduces code maintenance
while not leaving the “door open” for miscreants in the future.
4 – Endo Testing [3]
Our first three techniques all centered upon the idea of
“building the dependency elsewhere”. In direct dependency injection, it is
built by the client/test. When using a
service locator, it is built by the locator.
In using a DIF, the framework tool creates it. Endo testing is a way to avoid creating this
separation while still allowing the dependency to be injected.
Techniques are good to know about, but beware the overuse of any
code tricks you happen to know. Remember
that good separation is probably a good idea anyway, and just because you know how to do something does not mean you should.
To start, we change BoundaryAlarm in a different way:
public class BoundaryAlarm {
private GPS myGPS;
public BoundaryAlarm(){
myGPS = MakeGPS();
}
public void CheckFieldLocation(){
// Implementation unchanged
}
protected
virtual GPS MakeGPS() {
return new GPSImpl();
}
}
We have not gone to the extent of creating a new entity to
manage the instantiation of the GPS
dependency, we’ve simple done it in its own method. This would be a very simple refactor of the
original code, something most IDE’s would do for you as part of their built-in
refactoring tool suite.
However, note that the method is both protected and virtual (marked that way in a language like C#, or that
way by default in a language like Java).
That’s the trick: it allows the test of BoundaryAlarm
to actually create a subclass to be tested.
Ideally, this will be a private, inner class of the test:
[TestClass]
public class
BoundaryAlarmTest
private GPSMock mock;
[SetUp]
public void initializeTest() {
Mock = new GPSMock();
}
public
void testBoundaryAlarmRespondsToGPS() {
BoundaryAlarm testAlarm = new
TestableBoundaryAlarm();
//The body of the test, conditioning
the mock
//as needed
}
private
class TestableBoundaryAlarm : BoundaryAlarm {
protected override MakeGPS() {
return mock;
}
}
}
The trick here is that the test creates a subclass of the class being testing (TestableBoundaryAlarm subclasses BoundaryAlarm) but the only thing it overrides is the method that builds the dependency, causing it to build the mock instead. The test is essentially “reaching inside” the class under test to make this one single change.
This trick can be used to solve other problems involving
dependencies. For example, we often
develop code that couples directly to system/frameworks entities such as the date/time API, a network socket, the system
console, random number generation, and the like. We can wrap access to simple entities in
local methods, and then override those methods in the test.
Let’s take the system console.
If you’re writing directly to it, it’s very difficult for the test to
see what you’ve written, and specify what it should be. You could create a mock of the class that
represents the console, and perhaps you would.
But, if it was a simple issue and making a mock seemed like overkill,
you could wrap the console in a local method.
public class
MessageSender {
public void SendMessage() {
Output(“Ground control to Major
Tom.”);
}
protected virtual void Output(String
message) {
Console.WriteLine(message);
}
}
Now, in our test, we simply subclass MessageSender, override the Output method to simply write the message
into a local String, or keep a log of all writes, or whatever is most
convenient to the test. You could do the
same with a network connection, or an http request, or… whatever.
Conclusions
All systems are built using dependencies between entities
and yet these entities must be tested in isolation from one another, in order
to create narrow, precise specifications of their behaviors. The ability to create and inject mocks of
other entities when testing a given entity that is dependent on them is crucial
in TDD. The more techniques we learn,
and the more we innovate as technology changes, the more efficient we can be in
breaking these dependencies.
One thing we will want to examine is the role of Design
Patterns in all of this. If a pattern is
(as we believe) a collection of best practices for solving problems that recur,
surely the pattern should include best practices for testing it. Once we figure out how to test, say, the
Chain of Responsibility (where the mock object goes, what it does, etc…) we see
no reason to ever have to figure it out again.
So, stay tuned for that discussion!
[1] Unfamiliar with the Singleton Pattern? See: www.netobjectives.com/PatternRepository/index.php?title=TheSingletonPattern
[2] And you can get it here: http://docs.structuremap.net/
[3] This technique was originally suggested by Alex Chaffee
and Bill Pietri at IBM’s Developerworks: see http://www.ibm.com/developerworks/library/j-mocktest/index.html
Friday, June 8, 2012
Mock Objects, Part 2
Download the podcast.
Techniques
There are many ways to create a mock object by hand. You will likely come up with your own techniques, which may make use of language elements and idioms made possible by the particular languages and frameworks you work with. It is important to know more than one technique because under various circumstances during the development process we are able and unable to change different things. Also, we may be dependent on the work of other teams or organizations who might not have created an ideal situation for us if we seek to write the kinds of tests this book is about.
For example, let’s say the group who implemented the GPS system did not create a separate interface for their implementation, but instead just created a concrete API object that gives us access to the hardware:
No Interface for the GPS dependency |
I suppose we could take our testing laptop out into the field, hook it up to the real global positioning hardware, and physically move the system around the field, running the test in different locations. At some point, no doubt, such testing will take place. But remember, in TDD we are not really testing, we are specifying, and the spec should be useful and runnable at any point in time, under any circumstances. So, we must mock the GPS class.
Let’s start simply:
Direct Inheritance |
Here we have simply sub-classed the “real” GPS class. As was the case when GPS was an interface, our mock will up-cast and appear (to BoundaryAlarm) to be the real thing. The extra method SetCurrentLocation() will be available to the test, for conditioning purposes, because the test will hold the reference to the mock in a down-cast to its actual type.
But this technique may not work, or may product negative effects.
- If GPS is not able to be sub-classed (it is final, or sealed, or whatever your language would call a class that cannot be sub-classed), then this is obviously not possible.
- If the language you are using has both virtual and non-virtual methods, the GetCurrentLocation() method must be a virtual method, otherwise the up-cast of the mock will cause the original method to actually be called, rather than the mock’s method, and the test will not work.
- In sub-classing, you create strong coupling between the mock and the original class. One effect of this is the fact that when the test creates an instance of the mock (using new MockGPS()), the class loader will also create an instance of the base class (GPS) in the background. It must do this, as the original implementation methods are available to the sub-class (via Base() or super() or a similar method, or by direct access). If merely creating an instance of GPS is a disadvantage (it slows down the test, or requires that the actual hardware must be present when the test runs, etc…) then sub-classing like this is something we don’t want.
We could wrap the interface in an adapter (we’ll leave DashLight out of the discussion from this point forward):
Wrapping the dependency |
GPSWrapper is our class, which we created just for this purpose, so we could mock it. Clearly we would have to change BoundaryAlarm in this case, as it no longer directly depends on GPS but rather on the GPSWrapper, and these two are not interchangeable. But, if we can change BoundaryAlarm and cannot change GPS, then this technique is appropriate.
Note that the adapter and the “real” GPS have the same method name in this example. This is for simplicity; we could have called the method in the adapter anything we chose. If the team implementing the real GPS chose a method name we disliked (maybe we think it is unclear, or overly generic) this is also an opportunity to change this, and to make our code more readable.
Note also that the adapter is kept extremely simple; we are not going to be able to test it in TDD (we will do so in integration testing, but those are not run frequently) and so we really don’t want it to have any kind of complex behavior that might fail. We’ll probably do something like this:
public GPSWrapper {
private GPS myGPS;
public GPSWrapper() {
myGPS = new GPS();
}
public virtual Location GetCurrentLocation() {
return myGPS.GetCurrentLocation();
}
}
There’s very little to this, and that’s intentional. Whenever we create object like this (to wrap any dependency, like the database, the UI, the network, whatever) we call them “periphery objects” because they live on the boundary between the system we are developing and are responsible for, and other systems that we seek to control by mocking. We obviously cannot write TDD-style tests for these objects, and so we always keep them as minimal as possible.
This solves most of the problems of direct inheritance. Even if GPS is sealed and has non-virtual methods, our wrapper does not have these problems since we can create it any way we like. However, note that the inheritance from the mock to the wrapper still means that the real wrapper will be instantiated at test time, and since the wrapper creates an instance of the original GPS object we may still find our test is too slow, or can only be run in the presence of the hardware, etc… If this is a problem, we can take this one step further, and create an interface for wrapping:
Interface for Wrapping |
This eliminates the inheritance coupling between the mock and the implementation entirely, and thus we create no instance of the actual wrapper implementation (GPSWrapperImp) at test time. Our tests will run fast, be completely repeatable, and will not require the actual GPS system to run.
These are all techniques for creating mocks by hand. Another approach is to use a mocking
framework, a tool that creates these mocks for you. We’ll examine an example of such a tool a bit
later on, and also discuss what we like and dislike about the use of such
tools. In any case, whether you automate
you mocks or write them by hand, every developer should know how to handcraft
them, how they work, and what they do.
Next, in part 3, we’ll deal with different ways of injecting the mock into the class under test. In these examples the issue was simple: the constructor of BoundaryAlarm takes its two dependencies as parameters, allowing the test to send in the mock instead of the actual object. But what if we didn’t have this? We need more techniques, and we’ll examine a few.
Subscribe to:
Posts (Atom)