Series: Oracle ADF Development Essentials - Part 5


Unit Testing Your Application with JUnit

A primer on creating unit tests for Oracle Application Development Framework projects and executing them from within Oracle JDeveloper.

By John Stegeman

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 Concepts

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

  • Test method: a method in a Java class that contains a single unit test.
  • Test class: a Java class containing one or more test methods.
  • Assertion: a statement that you include in a test method to check that the results of a test are as expected.
  • Test fixture: a class that is used to set up state for multiple tests; typically used when the set up routines are “expensive” or take a long time to execute.
  • Test suite: a grouping of test classes that are run together.

Installing the JUnit Extensions

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....

    Figure1

    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:

    Figure2

    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:

    Figure3

    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.

What Should I Test?

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.

  • They test a small bit (or “unit”) of code. If the tests test “too much,” then they become less useful, as it will not be clear which bit of code is causing the test to fail.
  • They do not depend on external resources such as databases. The reason for this is so that the tests can be run in a variety of environments ( for example, the IDE  or build farms ) and so that multiple concurrent executions of the unit tests do not interfere with each other.
  • They should run quickly. This is to encourage the tests to be run as often as possible, even as often as every compile. If the tests take too long to execute, developers will be less likely to run them often.

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.

Creating the Unit Test Project

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:

Figure4

Figure 4 Creating a New Project

Leave Generic Project selected in the New Gallery dialog box and click OK:

Figure5

Figure 5 Selecting a Generic Project

Provide an appropriate name (such as “ModelTests”) for the project and click Finish:

Figure6

Figure 6 Naming the Tests Project

Creating Unit Tests

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:

Figure7

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:

Figure8

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 click Finish:

Figure9

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:

Figure10

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:

Figure11

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:

Figure12

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:

Figure13

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:

Figure14

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:

Figure15

Figure 15 Unit Test for Department Name 4-character Minimum

Here is what happens when we run the test suite:

Figure16

Figure 16 Test Failure for New Requirement

If you click on the failed test, you can even see why the test failed:

Figure17

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:

Figure18

Figure 18 All Tests Succeeding Again

Test Fixtures and Test Suites

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:

Figure19

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):

Figure20

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.

Using Ant to Automate JUnit

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.
  2. Add a path reference in jdev-libs.xml to refer to the JUnit 4.4 library:

    Figure21

    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:

Figure22

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:

Figure23

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:

Figure24

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:

Figure25

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:

Figure26

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:

Figure27

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:

Figure28

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):

Figure29

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.

Conclusion

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.

Go to Part 6 | Back to TOC

 

Resources



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.