« 8. General Design Principles | Main | 6. Basic Pattern - #3 Domain Test Object (DTO) »

December 10, 2004

7. Basic Pattern #4 - Transporter

Definition

Create a central authority that navigates through the application on behalf of tests.

Discussion

Similar to the Object Genie is the concept of a Transporter. Whereas the Object Genie grants tests whatever objects they need, a Transporter encapsulates navigation code so that tests don't have to know the details of how to move around the application. Instead, tests use the Transporter to navigate throughout the application on their behalf.

If the application changes so that users must now alter the way they navigate to a specific module, the modifications would be localized to the Transporter and changes would automatically cascade to all tests that use that Transporter. This reduces maintenance costs since none of the tests would be affected by this change and facilitates creating new tests since there is less test code to write.

Example

Each test needs a way to navigate to pages and then perform specific actions (e.g. log in, enter a coupon, buy an item on special, etc.). To use a coupon, one must first do the following navigations: login and navigate to the checkout page. There must also be items in the cart to which the coupon applies - this is taken care of by the Object Genie. The following code samples demonstrate the creation and use of a Transporter that navigates to the login and checkout pages.


Figure 8: Defining a Transporter.

public class Transporter {
public static void login() {
//Tool specific code to navigate to login screen and login to the application
}
public static void gotoCheckout() {
//Tool specific code to navigate to the checkout page
}
}


Figure 9: Using a Transporter.

import junit.framework.*;
public class CouponTest extends TestCase {
public CouponTest(String pName) { super(pName); }
public static Test suite() { return new TestSuite(CouponTest.class); }
protected void setUp() {
Transporter.login(); // <---- loose coupling
ShoppingCart shoppingCart = CartGenie.getNonEmptyCart();
Transporter.gotoCheckout(); //<----- loose coupling
}
public void testCheckoutWithValidCoupon() { //tests for a valid coupon
applyValidCoupon();
checkCouponAccepted();
}
public void testCheckoutWithExpiredCoupon() { //test for an expired coupon
applyExpiredCoupon();
checkCouponRejected();
}
public void testCheckoutWithInvalidCoupon() { //test for an invalid coupon
applyInvalidCoupon();
checkCouponRejected();
}
//… specific implementations of test methods (e.g. applyValidCoupon())
}

By moving navigation to the login and checkout pages to a central location, we allow other tests to reuse that functionality. The CouponTest class is now only responsible for testing coupon functionality without worrying about the details of how to get to the coupon page. This loose coupling makes the test more maintainable.

Posted by Misha Rybalov at December 10, 2004 05:08 PM

Comments

Post a comment




Remember Me?