Introducing JUnit


For writing unit tests for Java, we have to look no further than JUnit, an open source testing framework initially developed by Kent Beck and Erich Gamma. JUnit has become the de facto standard for Java unit testing. It is well supported by most development tools, and a wealth of reference material, tutorials, and other literature is available on its use.

The JUnit framework provides a ready-made test harness for executing unit tests as well as an API for reporting the success or failure status of a test. The JUnit framework is available for download from http://www.junit.org.

The success of JUnit is due in part to its simple design, as JUnit is both easy to learn and work with. Listing 14-1 shows the basic structure of a JUnit test case.

Listing 14-1. JUnit Test Case
 package customer.admin.ejb; import junit.framework.TestCase; public class CustomerAdminBeanTest extends TestCase {   protected void setUp() throws Exception {     super.setUp();   }   protected void tearDown() throws Exception {     super.tearDown();   }   public CustomerAdminBeanTest(String arg0) {     super(arg0);   }   public final void testValidateAccount() {     //TODO Implement validateAccount().   } } 

The example unit test shown in Listing 14-1 was automatically generated using Eclipse for a session bean with a single business method, validateAccount(). In its current state, the code shown isn't going to be performing much of a test, as we still have to add the testing functionality to the class. Nevertheless, the code does illustrate the structure of a JUnit test case.

To create a test that can be executed by the JUnit framework, you must write a test class responsible for conducting the individual test. This is achieved by defining a subclass of TestCase.

For each method on the class under test, a test method is required in the testing class. The method name should be prefixed with test. Methods must also be public, have no parameters, and return void. Adhering to these rules means the JUnit framework can use Java reflection to identify the test methods on the class dynamically. Without this approach, it would be necessary for all test methods to be registered with JUnit for execution. Reflection therefore simplifies the process of setting up a test case.

The basic test shown in Listing 14-1 contains only a single test method, testValidateAccount(). All the preparation work for the test can be done inside of this methodfor example, instantiating objects required for the test or creating database connections. All of this test preparation, however, clutters the test codesomething we must avoid, since a test should be easily readable.

For this reason, TestCase has two protected methods that can be overridden to provide setup and housekeeping tasks. The setUp() method is run before each test, while tearDown() is run once the test has completed.

Tip

The setUp() and tearDown() methods are run before every test method in the TestCase. If you have a setup-type operation that needs to be performed just once for all tests within the TestCase, then you must do this in the constructor. However, be wary of all code that is placed within the constructor, as JUnit simply reports that the test case could not be instantiated if an error occurs. A more detailed stack trace can be obtained from JUnit if setUp() is used.


You can confirm expected results at each step of the test's execution with the JUnit API. JUnit provides a number of assert methods for this purpose, where a failed assertion causes JUnit to report that the test has failed. Table 14-1 lists the different assertion types provided by JUnit for determining the status of an executing test.

Table 14-1. JUnit Assertion Types

Assert Type

Description

assertEquals

Asserts that two items are equal.

assertFalse

Asserts that a condition is false.

assertNotNull

Asserts that an object isn't null.

assertNotSame

Asserts that two objects do not reference the same object.

assertNull

Asserts that an object is null.

assertSame

Asserts that two objects refer to the same object.

assertTrue

Asserts that a condition is true.

fail

Fails a test unconditionally.


Listing 14-2 shows a complete test. In the example, the CustomerAdminBean session bean is tested from outside of the container using the remote interface of the enterprise bean.

Listing 14-2. CustomerAdminBeanTest.java with Complete Test
 package customer.admin.interfaces; import java.util.Hashtable; import javax.naming.InitialContext; import junit.framework.TestCase; import customer.domain.Customer; import customer.factory.CustomerFactory; public class CustomerAdminBeanTest extends TestCase {   private CustomerAdminBean customerAdminBean = null;   /**    * Obtain a remote interface to the Customer EJB.    */   protected void setUp() throws Exception {     super.setUp();     Hashtable props = new Hashtable();     props.put(InitialContext.INITIAL_CONTEXT_FACTORY,        "weblogic.jndi.WLInitialContextFactory");         props            .put(InitialContext.PROVIDER_URL, "t3://localhost:7001");         customerAdminBean = CustomerAdminBeanUtil.getHome(props)             .create();   }   /**    * Expects the class under test to declare the Customer does not have a valid    * account, i.e. method should return false    *    * @throws Exception    */   public final void testValidateAccount() throws Exception {     Customer customer = CustomerFactory.getCustomer(1);     assertFalse(customerAdminBean.validateAccount(customer));   } } // CustomerAdminBeanTest 

The setUp() method obtains the remote interface for the session. The tearDown() method has been removed, as we won't be performing any housekeeping in this example. The actual test is provided in the testValidateAccount() method. The expected result from the test is that the validateAccount() method on the session bean will correctly determine the Customer has an invalid account and will return a value of false. To verify this condition, the call to the session bean is wrapped in an assertFalse() statement.

With the test created, the next step is to execute the test and examine the results. Running unit tests should be as quick and painless as possible. The next section discusses some of the options for invoking test cases.

Running JUnit Tests with Eclipse

For executing test cases, JUnit uses a TestRunner. THRee versions of TestRunner are available, depending on how you wish to execute the tests:

  • junit.textui.TestRunner directs all test output to stdout.

  • junit.awt.ui.TestRunner provides a graphical AWT-based user interface for running tests.

  • junit.swingui.TestRunner provides a Swing-based graphical user interface for executing tests.

Although the JUnit framework provides the necessary tools for executing tests, it is preferable if the testing process integrates into your chosen development workbench.

Having an IDE that can run unit tests leads toward the goal of a single workbench as a one-stop shop for J2EE development. Rather than jumping out of the IDE in order to execute test cases, it is far more productive to have the IDE perform this operation.

The Eclipse workbench, like most IDEs, has excellent support for JUnit and comes with all of the necessary JUnit libraries as part of the install. Using an IDE like Eclipse, it is a trivial matter to execute all test cases and receive immediate feedback of the results of a test run.

An overview of the Eclipse workbench is provided in Chapter 13.


Figure 14-1 shows the Eclipse JUnit Fast View. This view is displayed after telling Eclipse the TestCase instance is to be run as a JUnit test. This action is invoked from the Eclipse run menu.

Figure 14-1. Eclipse JUnit Fast View.


The results of the CustomerAdminBeanTest test case are displayed in Figure 14-1, and in this instance, it is a failed test. The results of the test run are represented by a colored bar at the top of the view. Green is a pass and red is a fail. Figure 14-1 shows a red bar indicating failure. The reasons for the failure are given in the lower pane. In the example, we have an assertion failure: the validateAccount() code failed to correctly recognize an invalid customer account.

Having Eclipse make the running of tests so convenient allows for a rapid development cycle. The developer can update code and launch the test for immediate feedback on the success of the change.

Being able to run tests quickly is one factor in building a rapid development environment. Another is the time taken to write the test case. If we are going to embrace a test-first approach as part of a development methodology, then we need to consider how to reduce the time taken to write the tests.

Now that you have an appreciation of what is involved in writing a JUnit test, let's look at some of the options for expediting the development of a test suite.



    Rapid J2EE Development. An Adaptive Foundation for Enterprise Applications
    Rapid J2EEв„ў Development: An Adaptive Foundation for Enterprise Applications
    ISBN: 0131472208
    EAN: 2147483647
    Year: 2005
    Pages: 159
    Authors: Alan Monnox

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