Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers 10g (10.1.3.1.0) Part Number B25947-01 |
|
|
View PDF |
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.
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:
Select the business components project in your workspace that contains the application module.
Select the application module in that project for which you want to create a test suite.
Enter a configuration name to use for running the tests.
Click Finish to create the test suite.
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 ViewInstanceName
Test
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.
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; } }
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.
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.
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 assert
Xxxx
()
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.
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>
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.
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: TheUnitTests 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. |
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.