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

Four-Phase Test

The book has now been published and the content of this chapter has likely changed substanstially.
Please see page 358 of xUnit Test Patterns for the latest information.
How do we structure our test logic to make what we are testing obvious?

Structure each test with four distinct parts executed in sequence.

Sketch Four Phase Test embedded from Four Phase Test.gif

How It Works

We design each test to have four distinct phases that are executed in sequence. The four parts are fixture setup, exercise SUT, result verification and fixture teardown.

Why We Do This

It is important for the test reader to be able to quickly determine what behavior the test is verifying. It can be very confusing when various behaviors of the system under test (SUT) are being invoked, some to set up the pre-test state (fixture) of the SUT, others to exercise the SUT and yet others to verify the post-test state of the SUT. Clearly identifying the four phases makes the intent of the test much easier to see.

The fixture setup phase of the test establishes the prior state of the test which is an important input to the test. The exercise SUT phase is where we actually cause the software we are testing to run. hen reading the test, it is important to be able to see what software is being run. The result verification phase of the test is where we specify the expected outcome. The final phase, fixture teardown, is all about housekeeping. We wouldn't want to obscure the important test logic with it because it is completely irrelevant from a Tests as Documentation (see Goals of Test Automation on page X) perspective.

We should avoid the temptation to test as much functionality as possible in a single Test Method (page X) because that can result in Obscure Tests (page X). In fact, it is preferable to have many small Single Condition Tests (see Principles of Test Automation on page X). Using comments to mark the phases of a Four-Phase Test is a good source of self-discipline in that it makes it very obvious when our tests are not Single Condition Tests. It will be self-evident if we have multiple exercise SUT phases separated by result verification phases or we have interspersed fixture setup and exercise SUT phases. Sure, the tests may work but they will provide less Defect Localization (see Goals of Test Automation) than if we have a bunch of independent Single Condition Tests.

Implementation Notes

We have several options for implementing the Four-Phase Test. In the simplest case, each test is completely free-standing. It does all four phases of the test within the body of the Test Method. This implies we are using Inline Setup (page X) and either Garbage-Collected Teardown (page X) or Inline Teardown (page X). This is the most appropriate choice when we are using Testcase Class per Class (page X) or Testcase Class per Feature (page X) to organize our Test Methods. In some cases it may be advantageous to set up common parts of the fixture using Implicit Setup (page X) and do the remaining setup within the Test Method.

The other choice is to take advantage of the Test Automation Framework's (page X) support for Implicit Setup and Implicit Teardown (page X). We factor out the common fixture setup and fixture teardown logic into setUp and tearDown methods on the Testcase Class (page X). This leaves only the exercise SUT and result verification phases in the Test Method. This approach is appropriate choice when we are using Testcase Class per Fixture (page X).

Example: Four Phase Test (Inline)

Here is an example of a test that is clearly a Four-Phase Test:

   public void testGetFlightsByOriginAirport_NoFlights_inline() throws Exception {
      // Fixture setup
      NonTxFlightMngtFacade facade =new NonTxFlightMngtFacade();
      BigDecimal airportId = facade.createTestAirport("1OF");
      try {
         // Exercise System
         List flightsAtDestination1 = facade.getFlightsByOriginAirport(airportId);
         // Verify Outcome
         assertEquals( 0, flightsAtDestination1.size() );
      } finally {
         // Fixture teardown
         facade.removeAirport( airportId );
Example FourPhaseTestInline embedded from java/com/clrstream/ex6/services/test/FourPhaseTest.java

All four phases of the Four-Phase Test are included inline. Because the calls to Assertion Methods (page X) raise exceptions, we need to surround the fixture teardown part of the Test Method with a try/finally construct to ensure that is is run in all cases.

Example: Four Phase Test (Implicit SetUp/TearDown)

Here is the same Four-Phase Test with the fixture setup and fixture teardown logic moved out of the Test Method:

   NonTxFlightMngtFacade facade = new NonTxFlightMngtFacade();
   private BigDecimal airportId;
   protected void setUp() throws Exception {
      // Fixture setup
      airportId = facade.createTestAirport("1OF");
   public void testGetFlightsByOriginAirport_NoFlights_implicit() throws Exception {
      // Exercise SUT
      List flightsAtDestination1 = facade.getFlightsByOriginAirport(airportId);
      // Verify Outcome
      assertEquals( 0, flightsAtDestination1.size() );
   protected void tearDown() throws Exception {
      // Fixture teardown
Example FourPhaseTestImplicit embedded from java/com/clrstream/ex6/services/test/FourPhaseTest.java

Because the tearDown method is called automatically even after test failures, we don't need the try/finally construct inside the Test Method.

Page generated at Wed Feb 09 16:39:45 +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
Result Verification Patterns
Test Double Patterns
Test Organization
Test Refactorings
Test Smells
Test Strategy
Value Patterns
XUnit Basics
xUnit Members
All "XUnit Basics"
Test Method
--Four-Phase Test
Assertion Method
--Assertion Message
Testcase Class
Test Runner
Testcase Object
Test Suite Object
--Test Discovery
--Test Enumeration
--Test Selection