4.9 AbstractTest


Just like regular classes, abstract classes and interfaces should have their own unit tests. Designing such tests is not straightforward, because these object types cannot be directly instantiated . We'd also like to ensure that every descendant of an abstract class passes the parent object's tests. The AbstractTest pattern is the answer.

An AbstractTest is itself abstract, like the tested object. It contains an abstract factory method, which produces an instance of the object to test. It also contains the test methods for the abstract class. They resemble ordinary unit test methods , but test instances of the abstract class created by the factory method.

To test a concrete class that is descended from the abstract class, the unit test is subclassed from the AbstractTest. Its factory method returns an instance of the concrete class. When the concrete unit test is run, the AbstractTest is run as well. So, the AbstractTest tests every concrete implementation of the abstract class.

Let's create an AbstractTest for the interface DBConnection . We'll add the method isOpen( ) to it, as shown in Example 4-18.

Example 4-18. The interface DBConnection
 DBConnection.java public interface  DBConnection  {    void connect( );    void close( );    boolean isOpen( );    Book selectBook( String title, String author ); } 

The AbstractTest should test the behavior of the interface to make sure that any concrete implementation of it is correct. Tests of the isOpen( ) method should verify that it returns TRUE after connect( ) is called, and FALSE after close() is called. The AbstractTest class AbstractDBConnectionTestCase , shown in Example 4-19, provides these tests.

Example 4-19. The AbstractTest class AbstractDBConnectionTestCase
 AbstractDBConnectionTestCase.java import junit.framework.*; public abstract class  AbstractDBConnectionTestCase  extends TestCase {    public abstract DBConnection  getConnection( )  ;    public void  testIsOpen( )  {       DBConnection connection =  getConnection( )  ;       connection.connect( );       assertTrue( connection.isOpen( ) );    }    public void  testClose( )  {       DBConnection connection =  getConnection( )  ;       connection.connect( );       connection.close( );       assertTrue( !connection.isOpen( ) );    } } 

The AbstractTest specifies a factory method, getConnection() . Concrete tests that descend from it will implement the factory method, allowing the test methods testIsOpen( ) and testClose( ) to test an instance of the concrete class. Notice how these methods use getConnection() to get the DBConnection to test.

AbstractTests have names ending in "TestCase," which is different from other test classes. A separate naming convention for AbstractTest classes makes them easily recognizable. Some unit test tools assume that any class named ending with "Test" are test classes that should be instantiated and run, and the different naming convention avoids confusion.

To see the AbstractTest run, we need to define a concrete class descended from DBConnection and a corresponding concrete unit test descended from AbstractDBConnectionTestCase . The concrete class JDBCConnection is shown in Example 4-20.

Example 4-20. The concrete class JDBCConnection
 JDBCConnection.java public class  JDBCConnection  implements  DBConnection  {    private String  connectString  ;    private boolean  open  ;    public  JDBCConnection  ( String connect ) {       connectString = connect;       open = false;    }    public void  connect( )  { open = true; }    public void  close( )  { open = false; }    public boolean  isOpen( )  { return open; }    public String  getConnectString( )  { return connectString; }    public Book  selectBook  ( String title, String author ) {       return null;    } } 

JDBCConnection is an initial version of an interface to a JDBC database engine. It differs from the base DBConnection by its member connectString , which contains the URL of a JDBC database connection.

The unit test JDBCConnectionTest tests JDBCConnection . It is derived from the AbstractTest. It is shown in Example 4-21.

Example 4-21. The concrete test JDBCConnectionTest
 JDBCConnectionTest.java public class  JDBCConnectionTest  extends  AbstractDBConnectionTestCase  {    public DBConnection  getConnection( )  {       return new JDBCConnection( "jdbc:odbc:testdb" );    }    public void  testConnectString( )  {       JDBCConnection connection = (JDBCConnection)  getConnection( )  ;       String connStr = connection.getConnectString( );       assertTrue( connStr.equals("jdbc:odbc:testdb") );    } } 

JDBCConnectionTest implements the factory method getConnection( ) and one test method, testConnectString( ) . When the test is instantiated and run, the two test methods in the parent AbstractTest also will be run to test instances of JDBCConnection . This way, the AbstractTest verifies that the concrete subclass passes the tests of the parent interface.

Unit Test Frameworks
Unit Test Frameworks
ISBN: 0596006896
EAN: 2147483647
Year: 2006
Pages: 146
Authors: Paul Hamill

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net