Skip Headers
Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers
10g (10.1.3.1.0)

Part Number B25947-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

24.8 Regression Testing an Application Module With JUnit

Testing your business services is an important part of your application development process. By creating a set of JUnit regression tests that exercise the functionality provided by your application module, you can ensure that new features, bug fixes, or refactorings do not destabilize your application. JDeveloper's integrated support for creating JUnit regression tests makes it easy to follow this best practice. Its integrated support for running JUnit tests means that any developer on the team can run the test suite with a single mouse click, greatly increasing the chances that every team member can run the tests to verify their own changes to the system. Furthermore, by using JDeveloper's integrated support for creating and running Apache Ant build scripts, you can easily incorporate running the tests into your nightly build process as well. This section explains how to create a JUnit test for your application module, how to run it, and how to integrate the tests into an Ant build script.

24.8.1 How to Create a JUnit Test Suite for an Application Module

Typically you will create a separate project to contain your regression tests. For example, the SRDemo application has it JUnit regression test suite in the UnitTests project, while the business components that comprise its SRService application module belong to the DataModel project. After creating a new project to contain your JUnit test suite, you can use the Create Business Components Test Suite wizard in the context of that new project to create a JUnit test suite for an application module. You can find this wizard in the General > Unit Tests (JUnit) category in the New Gallery.


Tip:

If you don't see the Business Components Test Suite wizard, use JDeveloper's Help | Check for Updates feature to install the JUnit Integration for Business Components extension before continuing.

When the Test Suite Wizard dialog appears, perform the following steps on the Select Application page:

  1. Select the business components project in your workspace that contains the application module.

  2. Select the application module in that project for which you want to create a test suite.

  3. Enter a configuration name to use for running the tests.

  4. Click Finish to create the test suite.

24.8.2 What Happens When You Create a JUnit Test Suite for an Application Module

When you create a JUnit test suite for an application module using the wizard, JDeveloper updates the current project to have a dependency on the project containing the application module. In addition, assuming the application module for which you created the test suite were named devguide.example.ExampleModule, it generates the following skeleton classes in the devguide.example.test package:

  • A test suite class named ExampleModuleAllTests,

  • A test fixture class named ExampleModuleConnectFixture

  • A test class named ViewInstanceNameTest for each view object instance in the application module's data model

In this example, you would run the test suite at any time by running the ExampleModuleAllTests class.

24.8.3 What You May Need to Know

24.8.3.1 Test Suite Class Adds Test Cases to the Suite

By convention, a JUnit test suite is a class containing a public static method named suite() that returns an object that implements the Test interface in the junit.framework package. Typically, this will be an instance of the TestSuite class in that same package. The generated ExampleModuleAllTests class follows this convention to create and return an instance of this TestSuite object. As shown in Example 24-8, before returning the test suite it calls the addTestSuite() method to add one or more test case classes to the suite.

Example 24-8 Test Suite Class Adds Test Cases to the Suite

package devguide.example.test;
import junit.framework.Test;
import junit.framework.TestSuite;
public class ExampleModuleAllTests {
  public static Test suite() {
    TestSuite suite;
    suite = new TestSuite("ExampleModuleAllTests");
    suite.addTestSuite(ProductsTest.class);
    suite.addTestSuite(ServiceHistoriesTest.class);
    suite.addTestSuite(ServiceRequestsTest.class);
    // etc.
    return suite;
  }
}

24.8.3.2 Test Fixture Class Encapsulates Access to the Application Module

The generated ExampleModuleConnectFixture is a JUnit test fixture that encapsulates the details of acquiring and releasing an application. It contains a setUp() method that uses the createRootApplicationModule() method of the Configuration class to create an instance of an application module. Its tearDown() method calls the matching releaseRootApplicationModule() method to release the application module instance.

Each test case class contains a setUp() and tearDown() method that JUnit invokes to allow initializing resources required by the test case and to later clean them up. These test case methods invoke the corresponding setUp() and tearDown() methods to prepare and clean up the text fixture for each test case execution. Any time a test in the test case needs access to the application module, it access it using the test fixture's getApplicationModule() method. This returns the same application module instance, saved in a member field of the test fixture class, between the initial call to setUp() and the final call to tearDown() at the end of the test case.

24.8.3.3 JUnit Tests for an Application Module Must Use a JDBC URL Connection

The application module configuration that you use for a JUnit test suite needs to use a JDBC URL connection, rather than a JDBC datasource. This is due to the fact that JDBC datasources are defined by the J2EE application server and can only be referenced in the context of an application running inside the server. Your JUnit tests run outside the server environment. For example, the SRDemo application has two configurations defined for its SRService application module. The SRServiceLocal configuration uses a JDBC datasource. It is referenced in the DataBindings.cpx file of the UserInterface project for use in the SRDemo application. In contrast, the SRDemo's JUnit tests reference the SRServiceLocalTesting configuration. This uses a JDBC URL connection instead of a datasource.

24.8.3.4 Test Case Classes Contain One or More Test Methods with Assertions

Each generated test case can contain one or more test methods that the JUnit framework will execute as part of executing that test case. You can add a test to the test case simply by creating a public void method in the class whose name begins with the prefix test. For example, it might look like this:

// In ViewInstanceNameTest.java test case class
  public void testSomeMeaningfulName() {
  // test assertions here
  }

The wizard generates skeleton test case classes for each view object instance in the data model, each of which contains a single test method named testAccess(). This method contains a call to the assertNotNull() method to test that the view object instance exists.

Your own testing methods can use any of the programmatic APIs available in the oracle.jbo package to work with the application module and view object instances in its data model. You can also cast the ApplicationModule interface to a custom interface to have your tests invoke your custom service methods as part of their job. During each test, you will call one or more assertXxxx() methods provided by the JUnit framework to assert what the expected outcome of a particular expression should be. When you run the test suite, if any of the tests in any of the test cases contains assertions that fail, JDeveloper's JUnit Test Runner window displays the failing tests with a red failure icon.

24.8.4 Running a JUnit Test Suite as Parts of an Ant Build Script

Apache Ant is a popular, cross-platform build utility for which JDeveloper offers excellent design-time support. You can incorporate the automatic execution of JUnit tests and test output report generation by using Ant's built-in junit and junitreport tasks. Example 24-9 shows a task called tests from the SRDemo's Ant build.xml file in the BuildAndDeploy project. It depends on the build and buildTests targets that Ant will ensure have been executed before running the tests target.

The junit tag contains a nested test tag that identifies the test suite class to execute and specifies a directory in which to report the results. The junitreport tag allows you to format the test results into a collection of HTML pages that resemble the format of JavaDoc. To try running the SRDemo's JUnit test from this Ant task, select the build.xml file in the Application Navigator, and choose Run Ant Target > tests from the context menu.

Example 24-9 Ant Build Target Runs JUnit Test Suite and Generates Report

<!-- In SRDemo's build.xml -->
<target name="tests" description="Run the model layer Unit tests"
        depends="build, buildTests">
  <mkdir dir="${tests.reporting.dir}"/>
  <junit printsummary="true" fork="true">
    <formatter usefile="true" type="xml"/>
    <test name="oracle.srdemo.tests.model.SRServiceAllTests"
          todir="${tests.reporting.dir}"/>
    <sysproperty key="jbo.debugoutput" value="file"/>
    <classpath path="${model.build.dir}"/>
    <classpath path="${tests.build.dir}"/>
    <classpath refid="tests.classpath"/>
  </junit>
  <junitreport todir="${tests.reporting.dir}">
    <fileset dir="${tests.reporting.dir}">
      <include name="TEST-*.xml"/>
    </fileset>
    <report format="frames" todir="${tests.reporting.dir}"/>
  </junitreport>
</target>

24.8.5 Customizing the Default JUnit Test Classes

The SRDemo's UnitTest project includes examples of a few customizations you can make to the generated test case classes. This section describes how to customize the text fixture to authenticate a particular user and how to refactor common test case code in to a base class.

24.8.5.1 Customizing the Test Fixture to Run as an Authenticated User

The SRServiceFixture has a custom constructor that accepts a username and a password. Its setUp() method uses a custom ADF Business Components EnvInfoProvider implementation to supply runtime configuration parameters to the application module. In particular, to authenticate as the given username with the given password, the JUnitFixureLoginInfoProvider class implements the EnvInfoProvider interface's getInfo() method to return:

  • The value Must for the jbo.security.enforce property

  • The username value for the java.naming.security.principal property (referenced using the JboContext.SECURITY_PRINCIPAL constant)

  • The password value for the java.naming.security.credentials property (referenced using the JboContext.SECURITY_CREDENTIALS constant)

Each of the three test cases in the oracle.srdemo.tests.model.unittests package creates its instance of the SRServiceFixture with a different combination of username and password values. For example, the SRServiceTestAsManagerRole test case creates a SRServiceFixture for a user that has the manager role (sking). The other two tests each do the same, but for a user of the other two roles Technician and Manager.


Tip:

The UnitTests project in the SRDemo includes the ConfigurationData directory as one of its project contents paths. This ensures that the jazn-data.xml file (contained in its META-INF subdirectory) which defines all the users and roles for the demo, is readable by the JUnit tests at runtime. XML files in the project source path are copied to the project's output directory during compilation since their *.xml file extension is included by default in the Copy File Types to Output Directory field of the Compiler page in the Project Properties dialog.

24.8.5.2 Refactoring Common Test Case Code Into a Base Class

All three of the test case classes extend the SRUnitTestBase class. This class contains code that is common to all of the test cases. For example, it includes a number of helper methods for getting the current date, setting the current row in a view object by a stringified key, and creating a key of appropriate type for a given view object. It also defines the abstract method createSRServiceFixtureForTest() that each subclass overrides to return the SRServiceFixture constructed with the appropriate username and password for the authentication.