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

Implicit Setup

The book has now been published and the content of this chapter has likely changed substanstially.
Please see page 424 of xUnit Test Patterns for the latest information.
Also known as: Hooked Setup, Framework-invoked Setup, Setup Method

How do we construct the Fresh Fixture?

Build the test fixture common to several tests in the setUp method.

Sketch Implicit Setup embedded from Implicit Setup.gif

To execute an automated test, we require a text fixture that is well understood and completely deterministic. We are using a Fresh Fixture (page X) approach to build the Minimal Fixture (page X) for the use of this one test.

Implicit Setup is a way to reuse the fixture setup code for all the Test Methods (page X) in a Testcase Class (page X).

How It Works

All the tests in a TestCase class create identical Fresh Fixtures by doing test fixture setup in a shared setUp method on the TestCase class. The setUp method is called automatically by the Test Automation Framework (page X) before it calls each Test Method. This allows the fixture setup code placed in the setUp method to be reused without reusing the same instance of the test fixture. (I call this "implicit" set up because the calls to the fixture set up logic are not explicit within the Test Method as they are with Inline Setup (page X) and Delegated Setup (page X).

When To Use It

We can use Implicit Setup when we have several Test Methods on the same Testcase Class that need an identical Fresh Fixture. If all the Test Methods need the exact same fixture, then the entire Minimal Fixture needed by each test can be set up in the setUp method. This form of Test Method organization is known as Testcase Class per Fixture (page X).

When the Test Methods need different fixtures because we are using a Testcase Class per Feature (page X) or a Testcase Class per Class (page X), it is hard to use Implicit Setup and still build a Minimal Fixture. We can only use the setUp method to set up that part of the fixture which does not cause any problems for the other tests. A reasonable compromise is to use Implicit Setup to set up the parts of the fixture that are essential but irrelevant and leave the setting up of critical (and different from test to test) parts of the fixture to the individual Test Methods. Examples of "essential but irrelevant" fixture setup includes initializing variables with "don't care" values, initializing connections, etc. Fixture setup logic that directly affects the state of the system under test (SUT) can be left to the individual Test Methods unless every Test Method requires the same starting state.

The obvious alternatives for creating a Fresh Fixture are Inline Setup in which we include all the setup logic within each Test Method without factoring out any common code, and Delegated Setup in which we move all the common fixture setup code into a set of Creation Methods (page X) that we can call from within the setup part of each Test Method.

Implicit Setup removes a lot of Test Code Duplication (page X) and it also helps prevent Fragile Test (page X) by moving much of the non-essential interaction with the SUT out of the very numerous tests and into a much smaller number of places where it is easier to maintain. It can however lead to Obscure Tests (page X) caused by a Mystery Guest by making the test fixture used by each test less obvious. It can also lead to Fragile Fixture (see Fragile Test) if all the tests in the class do not really need identical test fixtures.

Implementation Notes

The main implementation considerations for Implicit Setup are:

Causing the Set Up Code to be Called

The use of the setUp method is the most common form of Implicit Setup; it consists of having the Test Automation Framework call the setUp method before each Test Method. Strinctly speaking, the setUp method is not the only form of implicit fixture set up. One other form is SuiteFixture Setup (page X) which is used to set up and tear down a Shared Fixture (page X) that is reused by the Test Methods on a single Testcase Class. Another is Setup Decorator (page X) which moves the setUp method to a Decorator[GOF] object installed between the Test Suite Object (page X) and the Test Runner (page X). Both are forms of Implicit Setup because the setUp logic is not explicit within the Test Method.

Tearing Down the Fixture

The fixture tear down counterpart of Implicit Setup is Implicit Teardown (page X). Anything that we set up in the setUp method that is not automatically cleaned up by Automated Teardown (page X) or garbage collection should be torn down in the corresponding tearDown method.

Accessing the Fixture

The Test Methods will need to be able to access the test fixture built in the setUp method. When they were used in the same method, local variables were enough. To communicate between the setUp method and the Test Method, the local variables need to be changed into instance variables. We must be careful not to make them class variables as this will result in the potential for a Shared Fixture. (See the sidebar There's Always an Exception (page X) for when this isn't true.)

Motivating Example

In the following example, each test needs to create a flight between a pair of airports.

   public void testStatus_initial() {
      // inline setup:
      Airport departureAirport = new Airport("Calgary", "YYC");
      Airport destinationAirport = new Airport("Toronto", "YYZ");
      Flight flight = new Flight(flightNumber, departureAirport,
                                 destinationAirport);
      // Exercise SUT & verify outcome
      assertEquals(FlightState.PROPOSED, flight.getStatus());
      // tearDown: //    garbage-collected
   }
  
   public void testStatus_cancelled() {
      // inline setup:
      Airport departureAirport = new Airport("Calgary", "YYC");
      Airport destinationAirport = new Airport("Toronto", "YYZ");
      Flight flight = new Flight( flightNumber, departureAirport,
                                  destinationAirport);
      flight.cancel(); // still part of setup
      // Exercise SUT & verify outcome
      assertEquals(FlightState.CANCELLED, flight.getStatus());
      // tearDown: //    garbage-collected
   }
Example InlineSetup embedded from java/com/clrstream/ex6/services/test/SetupStyles.java

Refactoring Notes

Note that there is a fair bit of Test Code Duplication between these tests. We can remove this duplication by refactoring this Testcase Class to use Implicit Setup. There are two refactoring cases to consider:

When we discover that all the tests are doing similar work to setup their test fixtures but are not sharing a setUp method, we can do an Extract Method[Fowler] refactoring of the fixture setup logic in one of the tests to create our setUp method. We will also need to convert any local variables to instance variables (fields) that hold the references to the resulting fixture until the Test Method can access it.

When we discover that a TestCase Class that already uses the setUp method to build the fixture has tests that need a different fixture, we can use an Extract Class[Fowler] refactoring to move all the Test Methods that need a different setup method to a different class. We need to ensure we take any instance variables that are used to convey knowledge of the fixture from the setup method to the tests with the setUp method. Sometimes it is just simpler to clone the Testcase Class and delete each test from one or the other copy of the class and then delete from each class any instance variables that are no longer being used.

Example: Implicit Setup

In this modified example we have moved all the common fixture setup code to the setUp method of our Testcase Class. This avoids the need to repeat it in each test. That makes each test much shorter which is a good thing.

  
   Airport departureAirport;
   Airport destinationAirport;
   Flight flight;
  
   public void setUp() throws Exception{
      super.setUp(); 
      departureAirport = new Airport("Calgary", "YYC");
      destinationAirport = new Airport("Toronto", "YYZ");
      BigDecimal flightNumber = new BigDecimal("999");
      flight = new Flight( flightNumber , departureAirport, destinationAirport);
   }
  
   public void testGetStatus_inital() {
      // implicit setup
      // Exercise SUT & verify outcome
      assertEquals(FlightState.PROPOSED, flight.getStatus());
   }
  
   public void testGetStatus_cancelled() {
      // implicit setup partially overriden:
      flight.cancel();
      // exercise SUT & verify outcome
      assertEquals(FlightState.CANCELLED, flight.getStatus());
   }
  
Example ImplicitSetup embedded from java/com/clrstream/ex6/services/test/ImplicitSetup.java

There are several disadvantages to this approach because we are not organizing our Test Methods around a Testcase Class per Fixture. (We are using Testcase Class per Feature here.) All the Test Methods on the Testcase Class must be able to make do with the same fixture (at least as a starting point) as evidenced by the partially overridden fixture setup in the second test. The fixture is also not very obvious in these tests. Where does the flight come from? Is there anything special about it? We cannot even rename the instance variable to communicate the nature of the flight better because we are using it to hold flights with different characteristics in each test.



Page generated at Wed Feb 09 16:39:35 +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 "Fixture Setup Patterns"
Fresh Fixture Setup:
--Inline Setup
--Delegated Setup
----Creation Method
--Implicit Setup
----Hooked Setup
----Framework-invoked Setup
----Setup Method
Shared Fixture Construction:
--Prebuilt Fixture
--Lazy Setup
--SuiteFixture Setup
--Setup Decorator
--Chained Tests