Software QA FYI - SQAFYI

Integration Testing for Java EE

By: Adam Bien

Pragmatic integration testing can increase your productivity and ensure the deployability of your Java EE 6 application.

In my previous article , “Unit Testing for Java EE”, I covered unit testing of Java Platform, Enterprise Edition 6 (Java EE 6) applications by mocking out all external dependencies with Mockito. Unit tests are important for the validation of application business logic, but they do not ensure the deployability of your Java EE 6 application.

Note: On Java.Net, you will find a Maven 3 project for this article, TestingEJBAndCDI, which was tested with NetBeans 7 and GlassFish v3.x.

Separation of (Performance) Concerns
Unit tests are fast and fine-grained. Integration tests are slow and coarse-grained. Instead of using arbitrary categorizations for unit and integration tests, such as “slow” or “fast,” to improve productivity, we could rely on their natural properties. Unit tests are finer-grained, so they should run first. You are usually writing small chunks of functionality, before the functionality is integrated into a larger subsystem. Unit tests are extremely fast. Hundreds of unit tests can be executed in milliseconds. You can iterate faster with unit tests, without waiting for the completion of integration tests.

Integration tests are performed after a successful execution of unit tests. Integration tests are, therefore, executed less frequently, because unit tests will naturally fail often. With this strict separation between unit tests and integration tests, we can save several minutes (sometimes, hours) with each turnaround.

Testing for Productivity
Pragmatic integration testing does increase your productivity. The low-hanging fruit is testing of Java Persistence API (JPA) mapping and queries. Deploying the whole application to the server just to test the syntactical correctness of mapping and queries takes too long.

Fortunately JPA persistence can be started directly in the unit test. The bootstrapping overhead is negligible. You only have to create the EntityManager with the EntityManagerFactory. For a mapping test of the Prediction entity, a real EntityManager instance is injected into the PredictionAudit class (see Listing 1).

public class PredictionAuditIT {

private PredictionAudit cut;

private EntityTransaction transaction;

@Before

public void initializeDependencies(){

cut = new PredictionAudit();

cut.em = Persistence.createEntityManagerFactory("integration").createEntityManager();

this.transaction = cut.em.getTransaction();

}

@Test

public void savingSuccessfulPrediction(){

final Result expectedResult = Result.BRIGHT;

Prediction expected = new Prediction(expectedResult, true);

transaction.begin();

this.cut.onSuccessfulPrediction(expectedResult);

transaction.commit();

List<Prediction> allPredictions = this.cut.allPredictions();

assertNotNull(allPredictions);

assertThat(allPredictions.size(),is(1));

}

@Test

public void savingRolledBackPrediction(){

final Result expectedResult = Result.BRIGHT;

Prediction expected = new Prediction(expectedResult, false);

this.cut.onFailedPrediction(expectedResult);

}

}

Listing 1: Injection of Unmanaged EntityManager
Since the EntityManager runs outside the container, the transactions can be managed only by the unit tests. Declarative transactions are not available in this case. This further simplifies the testing, because the transaction boundary can be explicitly set inside a test method. You can easily flush the EntityManager cache with an explicit EntityTransaction#commit() call. Right after the flush, the data is available in the database and can be validated for test purposes (see method savingSuccessfulPrediction in Listing 1).

Standalone JPA Configuration
EntityManager is part of the JPA specification and was already included with the glassfish-embedded-all dependency. Fortunately, the same dependency comes with the EclipseLink implementation. You need only an external database to persist the data. Derby database doesn’t require any installation and can be used in the server, embedded, and in an in-memory mode.

<dependency>

<groupId>org.apache.derby</groupId>

<artifactId>derbyclient</artifactId>

<version>10.7.1.1</version>

<scope>test</scope>

</dependency>

Listing 2: “Installing” the Derby Database

Derby is maintained in the standard Maven repository and can be included with a single dependency (see Listing 2). Test-scoped dependency is used, because the Java DataBase Connectivity (JDBC) driver is needed only at test execution time, and it doesn’t have to be deployed or installed on the server.

Because we are going to start the unit test outside the container, we cannot rely on the availability of Java Transaction API (JTA) transactions and javax.sql.DataSource.

<persistence version=“1.0” xmlns="http://java.sun.com/xml/ns/persistence
" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="integration" transaction-type="RESOURCE_LOCAL">
<class>com.abien.testing.oracle.entity.Prediction</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:derby:memory:testDB;create=true"/>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver"/>
<property name="eclipselink.ddl-generation" value="create-tables"/>
</properties>
</persistence-unit>
</persistence>


Listing 3: Unit Test-Specific persistence.xml Configuration

An additional, dedicated persistence.xml is created in the src/test/java/META-INF package and is used for testing exclusively. Because there is no deployment process, all entities have to be listed explicitly. Also transaction-type is set to RESOURCE_LOCAL, which enables manual transaction handling. Instead of a datasource declaration, the EntityManager talks directly to the database via the configured JDBC driver. The embedded Derby database configuration is the most convenient for unit testing. The EmbeddedDriver supports two connection strings: file persistence and in-memory persistence. For JPA mapping and query testing, the in-memory connection string (see Listing 3) is the way to go. All tables are created on-the-fly in memory before each test, and they vanish after the test execution. Because you don’t have to clean up your data after the test, this is the most convenient setup for JPA smoke tests.

More-complex JPA tests require a defined set of test data, which cannot be met with an in-memory setup. Derby database can also use files instead of memory to persist and load its data. You only have to modify the connection string for this purpose:

<property name="javax.persistence.jdbc.url" value="jdbc:derby:./sample;create=true”/>

In particular, tests requiring a predefined set of data can be conveniently performed with the file-persistence configuration. The populated database has to be copied into the project folder before the test execution and it has to be deleted afterwards. Hence, the database is deleted after each run. You don’t even have to worry about cleanup or any modifications.

Full article...


Other Resource

... to read more articles, visit http://sqa.fyicenter.com/art/

Integration Testing for Java EE