.com
Hosted by:
Unit testing expertise at your fingertips!
Home | Discuss | Lists

Hard-Coded Test Double

The book has now been published and the content of this chapter has likely changed substanstially.
Please see page 568 of xUnit Test Patterns for the latest information.
Also known as: Hard-Coded Mock Object, Hard-Coded Test Stub, Hard-Coded Test Spy

Variation of: Test Double


How do we tell a Test Double what to return or expect?

Build the Test Double by hard-coding the return values and/or expected calls.

Sketch Hard-Coded Test Double embedded from Hard-Coded Test Double.gif

Test Doubles (page X) are used for many reasons during the development of Fully Automated Tests (see Goals of Test Automation on page X). The behavior of the Test Double may vary from test to test. There are many ways to define this behavior.

When the Test Double is very simple and/or very specific to a single test, the simplest solution is often to hard-code the behavior right into the Test Double.

How It Works

The Test Double has all its behavior hard-coded right into it by the test automater. That is, if it needs to return a value for a method call, the value is hard-coded into the return statement. If it needs to verify that a certain parameter had a specific value, the assertion is hard-coded with the value that is expected.

When To Use It

We typically use a Hard-Coded Test Double when the behavior of the Test Double is very simple or if it is very specific to a single test or Testcase Class (page X). The Hard-Coded Test Double can be either a Test Stub (page X), a Test Spy (page X) or a Mock Object (page X) depending on what we encode in the method called by the system under test (SUT).

Because each Hard-Coded Test Double is purpose built by hand, it may take more effort than using a third-party Configurable Test Double (page X). It can also result in more test code to maintain and refactor as the SUT changes. If different tests require that the Test Double behave in different ways and the use of Hard-Coded Test Doubles results in too much Test Code Duplication (page X), we should consider using a Configurable Test Double instead.

Implementation Notes

Hard-Coded Test Doubles are inherently Hand-Built Test Doubles (see Configurable Test Double) because there tends to be no point in generating Hard-Coded Test Doubles automatically. Hard-Coded Test Doublescan be implemented with dedicated classes but they are most commonly used when the programming language supports blocks, closures or inner classes as these all help to avoid the file/class overhead associated with creating a Hard-Coded Test Double and it also keeps the Hard-Coded Test Double visible within the test that uses it. In some languages this can make the tests a bit harder to read, especially when anonymous inner classes are used because of all the syntactic overhead of defining the class inline. In languages that support blocks directly, and in which developers are very familiar with their usage idioms, it can actually make the tests easier to read.

There are many different ways to implement a Hard-Coded Test Double each with their advantages and disadvantages.

Variation: Test Double Class

We can implement the Hard-Coded Test Double as a separate class from either the Testcase Class or the SUT. This allows the Hard-Coded Test Double to be reused by several Testcase Classes but may result in Obscure Test (page X) (caused by a Mystery Guest) because it moves important indirect inputs or indirect outputs of the SUT out of the test to somewhere else, possibly out of sight of the test reader. Depending on how we implement the Test Double Class, it may also result in code proliferation and additional Test Double classes to maintain.

One way to ensure that the Test Double Class is type-compatible with the component it is to replace is by making it a subclass of that component. We then override any methods who's behavior we want to change.

Variation: Test Double Subclass

We can also implement the Hard-Coded Test Double by subclassing the depended-on component (DOC) and overriding the behavior of the methods we expect the SUT to call as we exercise it. Unfortunately, this can have unpredictable consequences if the SUT calls different methods. It also ties our test code very closely to the implementation of the depended on component and can result in Overspecified Software (see Fragile Test on page X). This may be a reasonable thing to do in very specific circumstance (say, while doing a spike) but I don't recommend it as a frequently used strategy.

Variation: Self Shunt


Also known as: Loopback

We can implement the methods that we want the SUT to call right on the Testcase Class and install the Testcase Object (page X) into the SUT as the Test Double to be used. This is called a Self Shunt.

Note that the Self Shunt can be either a Test Stub, a Test Spy or a Mock Object depending on what the method called by the SUT does. In each case, it will need to access instance variables of the Testcase Class to know what to do or expect. In statically typed languages, the Testcase Class will also have to implement the interface on which the SUT depends.

We typically use a Self Shunt when we need a Hard-Coded Test Double that is very specific to a single Testcase Class. If only a single Test Method (page X) requires the Hard-Coded Test Double it may be clearer to use an Inner Test Double if our language supports it.

Variation: Inner Test Double

A popular way to implement a Hard-Coded Test Double is to code it as an anonymous inner class or block closure within the Test Method. This gives it access to instance variables and constants of the Testcase Class and even the local variables of the Test Method and that can eliminate the need to configure it.

While the name of this variation is based on the name of the Java language construct of which it takes advantage, many programming languages have an equivalent mechanism for defining code to be run later using blocks or closures.

We typically use a Inner Test Double when we are building a Hard-Coded Test Double that is relatively simple and is only used within a single Test Method. Many people find the use of a Hard-Coded Test Double more intuitive than using a Self Shunt because they can see exactly what is going on within the Test Method. Readers unfamiliar with the syntax of anonymous inner classes or blocks may find the test hard to understand.

Variation: Pseudo Object

One of the challenges facing writers of Hard-Coded Test Doubles is that we must implement all the methods in the interface that the SUT might call. In statically-typed languages such as Java and C#, we must at least implement all the methods declared in the interface. This often "forces" us to subclass from the real DOC to avoid providing dummy implementations for each of these methods.

One way of reducing the effort is to provide a default implementation class that implements all the interface methods and throws a unique error. A Hard-Coded Test Double can then be implemented by subclassing this concrete class and overriding just the one method we expect the SUT to call while we are exercising it. If the SUT calls any of other methods, the Pseudo Object throws an error thereby failing the test.

Motivating Example

The following test verifies the basic functionality of component that formats an HTML string containing the current time. Unfortunately, it depends on the real system clock so it rarely ever passes!

   public void testDisplayCurrentTime_AtMidnight() {
      // fixture setup
      TimeDisplay sut = new TimeDisplay();
      // exercise sut
      String result = sut.getCurrentTimeAsHtmlFragment();
      // verify direct output
      String expectedTimeString = "<span class=\"tinyBoldText\">Midnight</span>";
      assertEquals( expectedTimeString, result);
   }
Example NondeterministicTest embedded from java/com/clrstream/ex7/test/TimeDisplayTest.java

Refactoring Notes

The most common transition is from using the real component to using a Hard-Coded Test Double(Moving from a Configurable Test Double to a Hard-Coded Test Double is pretty rare since we are usually looking to make the Test Double more reusable, not less.).To do this we need to build the Test Double itself and install it from within our Test Method. We may also need to introduce a way to install the Test Double using one of the Dependency Injection (page X) patterns if the SUT does not already support this. The process for doing this is described in the Replace Dependency with Test Double (page X) refactoring.

Example: Test Double Class

Here's the same test modified to use a Hard-Coded Test Double class to allow control over the time:

   public void testDisplayCurrentTime_AtMidnight_HCM() throws Exception {
      // fixture setup
      //   Instantiate hard-code Test Stub:
      TimeProvider testStub = new MidnightTimeProvider();
      //   Instantiate SUT:
      TimeDisplay sut = new TimeDisplay();
      //   Inject Stub into SUT:
      sut.setTimeProvider(testStub);
      // exercise sut
      String result = sut.getCurrentTimeAsHtmlFragment();
      // verify direct output
      String expectedTimeString = "<span class=\"tinyBoldText\">Midnight</span>";
      assertEquals("Midnight", expectedTimeString, result);
   }
Example HardCodedMockUsage embedded from java/com/clrstream/ex7/test/TimeDisplayTestSolution.java

This test is hard to understand without seeing the definition of the Hard-Coded Test Double. It is easy to see how this can lead to a Obscure Test caused by an Mystery Guest if the Hard-Coded Test Double is not close at hand.

   class MidnightTimeProvider implements TimeProvider {
      public Calendar getTime() {
         Calendar myTime = new GregorianCalendar();
         myTime.set(Calendar.HOUR_OF_DAY, 0);
         myTime.set(Calendar.MINUTE, 0);
         return myTime;
      }
   }
Example HardCodedMockDefn embedded from java/com/clrstream/ex7/test/TimeDisplayTestSolution.java

Depending on the programming language we are using, this Test Double Class can be defined in a number of different places including within the body of the Testcase Class (an "Inner Class") or as a separate free-standing class either in the same file as the test or in it's own file. But the farther we place it from the Test Method, the more of a Mystery Guest it becomes.

Example: Self Shunt

Here's a test that uses a Self Shunt to allow control over the time:

public class SelfShuntExample extends TestCase implements TimeProvider {
   public void testDisplayCurrentTime_AtMidnight() throws Exception {
      // fixture setup
      TimeDisplay sut = new TimeDisplay();
      // mock setup
      sut.setTimeProvider(this); // self shunt installation
      // exercise sut
      String result = sut.getCurrentTimeAsHtmlFragment();
      // verify direct output
      String expectedTimeString = "<span class=\"tinyBoldText\">Midnight</span>";
      assertEquals("Midnight", expectedTimeString, result);
   }
  
   public Calendar getTime() {
      Calendar myTime = new GregorianCalendar();
      myTime.set(Calendar.MINUTE, 0);
      myTime.set(Calendar.HOUR_OF_DAY, 0);
      return myTime;
   } 
}
Example SelfShunt embedded from java/com/clrstream/ex7/test/SelfShuntExample.java

Note how both the Test Method that installs the Hard-Coded Test Double and the implementation of the getTime method being called by the SUT are on the same class. We've used the Setter Injection (see Dependency Injection) pattern for installing the Hard-Coded Test Double. Because this example is in a statically-typed language, we have had to add the clause implements TimeProvider to the Testcase Class declaration so that the sut.setTimeProvider(this) statement will compile. In a dynamically-typed language, this would be unnecessary.

Example: Subclassed Inner Test Double

Here's a JUnit test that uses a Subclassed Inner Test Double using Java's "Anonymous Inner Class" syntax:

   public void testDisplayCurrentTime_AtMidnight_AIM() throws Exception {
      // fixture setup
      //    Define and instantiate Test Stub
      TimeProvider testStub = new TimeProvider() {
      // anonymous inner stub
         public Calendar getTime() {
            Calendar myTime = new GregorianCalendar();
            myTime.set(Calendar.MINUTE, 0);
            myTime.set(Calendar.HOUR_OF_DAY, 0);
            return myTime;
         }        
      };
      //   Instantiate SUT:
      TimeDisplay sut = new TimeDisplay();
      //   Inject Test Stub into SUT:
      sut.setTimeProvider(testStub);
      // exercise sut
      String result = sut.getCurrentTimeAsHtmlFragment();
      // verify direct output
      String expectedTimeString = "<span class=\"tinyBoldText\">Midnight</span>";
      assertEquals("Midnight", expectedTimeString, result);
   }
Example AnonymousInnerMock embedded from java/com/clrstream/ex7/test/TimeDisplayTestSolution.java

We have used the class name of the real depended-on class (TimeProvider) in the call to new for the definition of the Hard-Coded Test Double so we are actually creating an anonymous Subclassed Test Double inside the Test Method.

Example: Inner Test Double subclassed from Pseudo Class

Suppose we have replaced one implementation of a method with another that we need to leave around for backwards compatability but we want to write tests to ensure that the old method is no longer being called. This is easy to do if we already have the following Pseudo Object definition:

/**
 * Base class for hand-coded Test Stubs and Mock Objects
 */
public class PseudoTimeProvider implements ComplexTimeProvider {

   public Calendar getTime() throws TimeProviderEx {
      throw new PseudoClassException();
   }

   public Calendar getTimeDifference(Calendar baseTime, Calendar otherTime)
            throws TimeProviderEx {
      throw new PseudoClassException();
   }

   public Calendar getTime( String timeZone ) throws TimeProviderEx {
      throw new PseudoClassException();
   }
}
Example PseudoClass embedded from java/com/clrstream/ex7/test/PseudoTimeProvider.java

We can now write a test that ensures that the old version of the getTime method is not being called by subclassing and only overriding the newer version of the method (the one we expect to be called by the SUT) as follows:

   public void testDisplayCurrentTime_AtMidnight_PS() throws Exception {
      // fixture setup
      //    Define and instantiate Test Stub
      TimeProvider testStub = new PseudoTimeProvider()
      { // anonymous inner stub
         public Calendar getTime(String timeZone) {
            Calendar myTime = new GregorianCalendar();
            myTime.set(Calendar.MINUTE, 0);
            myTime.set(Calendar.HOUR_OF_DAY, 0);
            return myTime;
         }        
      };
      //   Instantiate SUT:
      TimeDisplay sut = new TimeDisplay();
      //   Inject Test Stub into SUT:
      sut.setTimeProvider(testStub);
      // exercise sut
      String result = sut.getCurrentTimeAsHtmlFragment();
      // verify direct output
      String expectedTimeString = "<span class=\"tinyBoldText\">Midnight</span>";
      assertEquals("Midnight", expectedTimeString, result);
   }
Example PseudoClassBasedInnerStub embedded from java/com/clrstream/ex7/test/TimeDisplayTestSolution.java

If any of the other methods are called, the base class methods are invoked and they throw an exception. Therefore, if we run this test and one of the methods we didn't override is called we will see the following as the first line of the JUnit stack trace for this test error:

   com..PseudoClassEx: Unexpected call to unsupported method.
   at com..PseudoTimeProvider.getTime(PseudoTimeProvider.java:22)
   at com..TimeDisplay.getCurrentTimeAsHtmlFragment(
      TimeDisplay.java:64)
   at com..TimeDisplayTestSolution.testDisplayCurrentTime_AtMidnight_PS(
         TimeDisplayTestSolution.java:247)
Example PseudoObjectFailureTrace embedded from java/com/clrstream/ex7/test/PseudoObjectFailureStackTrace.txt

In addition to failing the test, this makes it very easy to see exactly which method was called and works for all unexpected methods with no additional effort.

Further Reading

Many of the "how to" books on test-driven development provide examples of Self Shunt. These include [TDD-APG], [TDD-BE], [UTwJ], [PUT] and [JuPG]. The original write-up was by Micheal Feathers and is accessible at http://www.objectmentor.com/resources/articles/SelfShunPtrn.pdf

The original "Shunt" pattern is written up at http://http://c2.com/cgi/wiki?ShuntPattern along with a list of possible alternate names including "LoopBack". See the sidebar What's in a (Pattern) Name? (page X)
Include the sidebar 'What's in a (Pattern) Name?' on opposite page.
for a discussion of how to select meaningful and evocative pattern names.

The Pseudo Object pattern is described in the paper "Pseudo-Classes: Very Simple and Lightweight MockObject-like Classes for Unit-Testing" available at http://www.devx.com/Java/Article/22599/1954?pf=true.



Page generated at Wed Feb 09 16:39:42 +1100 2011

Copyright © 2003-2008 Gerard Meszaros all rights reserved

All Categories
Introductory Narratives
Web Site Instructions
Code Refactorings
Database Patterns
DfT Patterns
External Patterns
Fixture Setup Patterns
Fixture Teardown Patterns
Front Matter
Glossary
Misc
References
Result Verification Patterns
Sidebars
Terminology
Test Double Patterns
Test Organization
Test Refactorings
Test Smells
Test Strategy
Tools
Value Patterns
XUnit Basics
xUnit Members
All "Test Double Patterns"
Test Double
--Test Stub
--Test Spy
--Mock Object
--Fake Object
--Configurable Test Double
--Hard-Coded Test Double
----Hard-Coded Mock Object
----Hard-Coded Test Stub
----Hard-Coded Test Spy
----Test Double Class
----Self Shunt
----Loopback
----Inner Test Double
----Pseudo Object
Test-Specific Subclass