A primer on creating unit tests for Oracle Application Development Framework projects and executing them from within Oracle JDeveloper.
By John Stegeman
Series: Oracle ADF Development Essentials - Part 5
Published February 2010
Downloads:
For anything other than a very trivial application, you will find it important to test various components of the application to ensure that they are functioning correctly. As you continue developing and changing the components, having tests that you can re run after each change will enable you to test that your application’s components continue to function correctly. A generic architecture called xUnit exists for writing such automated unit tests. A specific instance of the xUnit architecture called JUnit is an open source package for developing automated unit tests in Java. This article explains how to use Oracle JDeveloper 11g to write and execute JUnit tests for testing Oracle Application Development Framework (Oracle ADF) applications.
JUnit is a program that can be used to perform unit testing of software by writing test cases in Java. A common use for JUnit is to create a set of unit tests that can be run automatically when changes are made to software; in this way, developers can ensure that changes to the software they are creating do not break things that were previously functioning. There is even a method of development known as test-driven development (TDD) that advocates writing unit tests even before writing the software under test itself. JUnit also provides a test runner that is capable of running the unit tests and reporting on the success or failure of the tests.
Some common terms that you may encounter when reading about JUnit include
Oracle JDeveloper 11g uses extensions to provide JUnit support. To install the extensions, perform the following steps:
1. From the Oracle JDeveloper Help menu, choose Check for Updates....
Figure 1 Checking for Updates
2. Ensure that, at a minimum, you have selected the “Official Oracle Extensions and Updates” update center, and click Next:
Figure 2 Update Centers
3. Type JUnit in the search box to search for the updates. At a minimum, include the BC4J JUnit Integration and JUnit Integration extensions, and click Next:
Figure 3 Selecting the JUnit Extensions
4. Agree to the license agreement and click Next. Provide your Oracle Technology Network (OTN) username and password if prompted. Oracle JDeveloper will download and install the extensions..
5. When prompted, click Finish to close the wizard and allow Oracle JDeveloper to restart in order to finish installing the extensions. Answer “No” when asked if you want to migrate settings from a previous version.
Now that the JUnit extensions are installed, you are ready to start creating unit tests. The first thing you might ask yourself is, “ For what should I write a unit test?” For Web applications such as the one you have been using throughout this article series, that is often one of the more difficult questions to answer. In general, unit tests should have the following characteristics.
For our simple application (a Web application used to maintain tables in a database), the first two of these general characteristics are somewhat difficult to achieve. In fact, the Wikipedia article on test-drive development acknowledges this: “Test-driven development is difficult to use in situations where full functional tests are required to determine success or failure. Examples of these are user interfaces, programs that work with databases....”
Although TDD advocates the use of “mock” objects to remove dependencies on external resources, a common compromise is to allow the use of a real database for unit tests. My experience (which has been mostly around writing enterprise applications; as a general rule, they have some type of database) has shown that this is a useful compromise. I try to write my unit tests so that they do not depend upon a specific database state, or if they do, the unit tests should create that expected state themselves. A later article in this series will show how to write functional ( Web user interface) tests that can be automated just as JUnit tests can be.
A good starting point for writing JUnit tests in an Oracle ADF application is in the Model layer. We can write unit tests to ensure that expected View Object instances are available from the appropriate application modules and check that our data validation rules are correctly accepting valid data and rejecting invalid data.
Because keeping unit tests separate from the rest of the application code will make it easier to create deployment artifacts such as EAR files that do not include the unnecessary-for-deployment unit tests, I usually create a separate project to hold the unit tests. Because we are going to create unit tests for our Model (Business Components) project, let us create a new project called “ModelTests” to hold the unit tests. With the otnapp application open in the Oracle JDeveloper IDE, choose New Project from the Application Navigator shortcut menu:
Figure 4 Creating a New Project
Leave Generic Project selected in the New Gallery dialog box and click OK:
Figure 5 Selecting a Generic Project
Provide an appropriate name (such as “ModelTests”) for the project and click Finish:
Figure 6 Naming the Tests Project
Now that we have a project, we can use the Business Components Test Suite Wizard to set up a basic set of JUnit tests for the Oracle ADF Business Components in our Model project, as well as a JUnit Test Fixture (for setting up the database connection) and a JUnit test suite (for running the generated tests). To do so, right-click the ModelTests project and select New... from the context menu:
Figure 7 Invoking New from the Context Menu
When the New Gallery appears, select the Unit Tests category and Business Components Test Suite item and click OK:
Figure 8 Invoking the Business Components Test Suite Wizard
On the first page of the JUnit ADF Business Components Test Suite Wizard, ensure that the Business Components Project (Model.jpr) is selected and that the proper Application Module (OTNAppModule) and Configuration (OTNAppModuleLocal) are selected, and clickFinish:
Figure 9 JUnit ADF Business Components Test Suite Wizard
Once you finish the wizard, Oracle JDeveloper will create the following files in the ModelTests project:
File | Purpose |
---|---|
AllOTNAppModuleTests.java | Test suite class |
OTNAppModuleAMFixture.java | Test fixture class that is used by all of the tests to obtain an instance of the application module so that each test does not have to create its own instance of the application module (for performance reasons) |
DepartmentsVOTest.java, DepartmentsVOTest.xml | Unit test class for the DepartmentsVO View Object |
EmployeesForDepartmentVOTest.java, EmployeesForDepartmentVOTest.xml | Unit test class for the EmployeesForDepartmentVO View Object |
Before we have a look at the code itself, let’s run the generated test cases and see what happens. JUnit uses the concept of a test suite to group tests together, so let’s run the generated test suite using Oracle JDeveloper’s JUnit test runner. To do so, right-click the test suite class (AllOTNAppModuleTests.java) in the Application Navigator and choose Run from the context menu:
Figure 10 Running the Test Suite
Once the tests run, you will be able to see the results in the JUnit Test Runner – Log window:
Figure 11 Test Suite Results
From this example, you can see that two unit tests were run and that both of them were successful (no failures or errors). Now, let’s have a look at the actual code behind the generated unit tests and add some of our own tests. Double-click the DepartmentsVOTest.java file in the Application Navigator to open the source code for the unit tests of the DepartmentsVO View Object:
Figure 12 Source Code for DepartmentsVO Unit Tests
The first thing you will notice is the use of Java 5 annotations in the code; these annotations are used to indicate to JUnit which methods are unit tests (with the @Test annotation) and which methods are run @Before or @After each unit test in the class. Unlike in previous versions of JUnit, the methods do not have to follow a specific naming convention for @Test, @Before, or @After methods. One thing to note is that JUnit does not guarantee the order of calling the @Before methods, the @Test methods, or the @After methods; the only guarantee is that all @Before methods are called before each @Test method, and all @After methods are called after each @Test method.
The Oracle JDeveloper –generated test class has one test method called testAccess that attempts to get a View Object instance from an application module (the application module was created by a test fixture— more on that later) and uses a JUnit assertion to ensure that the obtained View Object is not null. This is a common pattern for a unit test within JUnit: perform a test and then use one of the assert methods to verify the result. If the assertion is not true, then JUnit will flag the particular unit test as failed.
As you can see, the basic unit test generated by the wizard is quite simplistic. Let’s write our own unit test for this View Object to test that the Department ID attribute is being enforced as required. We can write such a unit test by creating a row, not setting the Department ID, validating the row, and seeing that the proper exception is thrown. But, how do we tell JUnit that we expect to see an exception (and furthermore that the test should fail if the exception is not thrown)? We do that by using the expected attribute of the @Test annotation to tell JUnit that we expect to see a certain exception. Oracle ADF should throw an oracle.jbo.AttrValException in the case we don’t supply a required attribute, so we can code our unit test like this:
Figure 13 Unit Test to Ensure Department ID is Required
If you run the test suite class again, you should see the additional test run successfully:
Figure 14 Running with an Additional Unit Test
So far, all of our tests have succeeded. Let’s do a bit of TDD now, based upon a new requirement just in from the user community: the Department Name must be at least 4 characters long. In the spirit of TDD, before we write a single line of code to implement this requirement, we must write the test for it and observe it failing. We can write a unit test for this requirement by trying to set the Department Name to a three-character string (with an expected exception) and running the test suite. Here is the test method:
Figure 15 Unit Test for Department Name 4-character Minimum
Here is what happens when we run the test suite:
Figure 16 Test Failure for New Requirement
If you click on the failed test, you can even see why the test failed:
Figure 17 Reason for Test Failure
We now have done the first step of TDD, namely to write a unit test for the new requirement and observe it failing (because we haven’t implemented the requirement yet). The next step is to implement the requirement. (I won’t show the steps here; simply add a length validation rule to the Departments Entity Object to enforce a minimum length of four characters.) Once we have done that, we can rerun the test suite and observe all tests succeeding:
Figure 18 All Tests Succeeding Again
The concept of test fixtures and test suites has evolved somewhat from earlier JUnit releases; however, the basic ideas have remained the same. A test fixture is designed to be used to perform any expensive set up or initialization for a group of related tests. The ADF Business Component JUnit Wizard generates a test fixture for you that does the expensive operation of creating an Oracle ADF Application Module instance for use by the rest of the unit tests.
Test suites are simply a logical grouping of test classes that can be run together as a group. The ADF Business Component JUnit Wizard generates a test suite for you that initializes the fixture and specifies, via the @Suite.SuiteClasses annotation, which test classes are part of the suite:
Figure 19 SuiteClasses Annotation in the Test Suite
As you add more test classes to your project, you can simply update the test suite’s @Suite.SuiteClasses annotation to include your newly created test classes. You can also create additional test suites simply by creating a new class and adding the annotations manually, or by using the Oracle JDeveloper JUnit Test Suite Wizard to create the class for you. To invoke the wizard, you can right-click your test project in the Application Navigator and click New..., and in the New Gallery that appears, select the Unit Tests category and Test Suite item (you may need to select the All Technologies tab to see the Unit Tests category):
Figure 20 Creating a New Test Suite
By creating additional test suites, you can group your unit tests into logical groupings, which allows you to run a subset of your unit tests at one time.
In order to fully leverage JUnit in a TDD approach, your unit tests should be run as often as possible . A common approach is to use a continuous integration (CI) server that builds your code and runs unit tests each time the code is committed to the version control system. A later article in this series describes how to set up such a continuous integration process. A common way of integrating JUnit tests with such CI servers is to add Anttargets to the build process for executing the tests; the CI server can then be set up to run the unit tests as part of the build process (and usually will “fail the build” if any JUnit test fails). In order to do this, we can follow the steps in the Ant article of this series to create an Ant build file for our ModelTests project. Assuming that you have followed the series up to this point, the steps (in short) are
1. Copy the junit-4.4.jar file from the Oracle JDeveloper installation directory to the corresponding location in the JDeveloperLibs project directory.
Add a path reference in jdev-libs.xml to refer to the JUnit 4.4 library:
Figure 21 JUnit 4.4 Library Reference
3. Add “Ant” to the technology scope for the ModelTests project and create a build file for that project.
4. Follow the steps in the Ant article to clean up the generated build.properties and build.xml files.
5. Remove the “copy” and “all” targets from the build.xml file.
6. Rename the existing targets to include a “ModelTests” prefix to avoid any name clashes.
Once you have performed these steps, your ANT build.xml file should look something like this:
Figure 22 Initial build.xml File
The next step is to create an ANT target for running the JUnit test suite. Fortunately, ANT includes a plug-in for running JUnit test suites and generating reports. Before we create the task, we will need to import the build file for the Model project so that we can add a dependency on compiling the Model classes before we test them. Add the following line to the ModelTest project’s build.xml file:
Figure 23 Importing the Model Project’s build.xml File
Now we can create an Ant task to execute our test suite; the JUnit plug-in for Ant will generate a test report, so we first need to add a line to our ModelTest project’s build.properties file to specify where the reports go:
Figure 24 Defining the Test Report Output Directory
Then, we update the ModelTests.clean and ModelTests.init targets to clean and create the test report directory:
Figure 25 Initializing and Cleaning the Test Report Directory
Next, we need to define a classpath for executing the Tests. The classpath will need to include the ModelTest project’s classpath, the Model project’s classpath, the output from both of those projects, and the .adf and src directories for the application (to get connection information). The resulting classpath in build.xml looks like this:
Figure 26 Test Execution Classpath
Finally, we can create the Ant task to actually execute our test suite. In the task, we specify the classpath, the test suite(s) to run, and the format to use for the test reports . XML is the best format to use with a CI server, so we’ll use it here:
Figure 27 Ant Task for Running the Test Suite
Now, we should be able to run our test suite by executing the appropriate Ant task.One option is to run it from within Oracle Jdeveloper:
Figure 28 Running the Test Suite via the Context Menu
The other option is to run the test suite from the command line (you may need to copy junit.jar and ant-weblogic.jar from the Oracle JDeveloper Ant installation into your standalone Ant installation for this to work):
Figure 29 Running the Test Suite from the Command Line
Now that you have everything working, don’t forget to commit all your changes to the Subversion Repository.
Figure 24 Defining the Test Report Output Directory
Figure 24 Defining the Test Report Output Directory
Now you have the basic knowledge you need to start using JUnit to write unit tests for your Oracle ADF applications. Although this article has focused on testing the Model layer, you can easily write unit tests for other classes in your application as well. Future articles in this series will show you how to write functional tests to test the User Interface layer and how to use a CI server to run your unit tests on a regular basis.
John Stegeman (http://stegemanoracle.wordpress.com) is an Oracle ACE director (Oracle Fusion Middleware) and the principal architect in the EMEA region for Cambridge Solutions, a global BPO and IT services firm. He has been working with Oracle products since 1990 and with Oracle JDeveloper since version 3.