Everybody knows that you need to write unit tests for your business code. But you also want to know when somebody (or you) breaks the configuration and that your Database Access Layer works properly.

DerbyDB LogoYou don’t want to test against an existing database instance! Your build can fail on unavailability, bad data, locks, etc and it will slow down your test. I’m using an in-memory database who’s launched together with the integration test and has some pre-defined data who’s always going to be the same for every test run. I’m using Derby who’s embedded into Glassfish but you can use any other in-memory database like hsqldb for example. Most of the available examples out there are using Derby for their application as well, I’m not, I’ve created a separated configuration for my tests. My tests are running on Derby and my application uses MySql.

Arquillian Logo

I’m using Arquillian to startup a Glassfish container. I can deploy all the classes who are required for the EJB I’m willing to test on the embedded container in the setup of the integration test. Arquillian is an new open source framework from jboss and recently they shipped version 1.0.2. You can use any JEE compatible container embedded or stand-alone, see their site for the list.

I can only advise you to test as much as possible with regular unit test using a mock framework like Mockito, integration tests will definitely slow down your build!  Never use it to test all of your business code. 

Tutorial

Maven

At first we need to setup our maven project. I’m using the following versions. Be careful when upgrading the version of Glassfish, newer version can sometimes be incompatible with a less recent Arquillian release.

  <properties>
     ...
     <arquillian.version>1.0.2.Final</arquillian.version>
     <arquillan.glassfish.embedded.version>1.0.0.CR3</arquillan.glassfish.embedded.version>
     <arquillian_persistence.version>1.0.0.Alpha5</arquillian_persistence.version>
     <glassfish.embedded.all.version>3.1.1</glassfish.embedded.all.version>
     <ejb.version>3.1</ejb.version>
     <jpa.version>2.0.0</jpa.version>
     <eclipselink.version>2.3.2</eclipselink.version>
     <mysql.version>5.1.19</mysql.version>
    ...
  <properties>

I’m using the arquillian-bom (Bill Of Material) who contains all the versions for the arquillian dependencies. (Except for arquillian-persistence which is a different project)

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.jboss.arquillian</groupId>
				<artifactId>arquillian-bom</artifactId>
				<version>${arquillian.version}</version>
				<scope>import</scope>
				<type>pom</type>
			</dependency>
		</dependencies>
	</dependencyManagement>

The arquillian dependencies:

		<dependency>
			<groupId>org.jboss.arquillian.junit</groupId>
			<artifactId>arquillian-junit-container</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.jboss.arquillian.extension</groupId>
			<artifactId>arquillian-persistence-api</artifactId>
			<version>${arquillian_persistence.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.jboss.arquillian.extension</groupId>
			<artifactId>arquillian-persistence-impl</artifactId>
			<version>${arquillian_persistence.version}</version>
			<scope>test</scope>
		</dependency>

Create a glassfish integration test profile, it’s possible to create multiple profiles to run your tests on multiple application servers.

		
	<profiles>
		<profile>
			<id>glassfish</id>
			<dependencies>
				<dependency>
					<groupId>org.jboss.arquillian.container</groupId>
					<artifactId>arquillian-glassfish-embedded-3.1</artifactId>
					<version>${arquillan.glassfish.embedded.version}</version>
					<scope>test</scope>
				</dependency>
				<dependency>
					<groupId>org.glassfish.extras</groupId>
					<artifactId>glassfish-embedded-all</artifactId>
					<version>${glassfish.embedded.all.version}</version>
					<scope>test</scope>
				</dependency>
			</dependencies>
		</profile>
	</profiles>

Don’t forget to enable the maven profile when you’re running your tests in eclipse and you’re using the m2ecilpse plugin. Right click on your project, choose properties > maven and enter glassfish as active maven profile.

As an alternative you can always run the tests with maven from the console with -Pglassfish as argument.

You might want to take a look at my complete pom.xml over here.

Hello EJB

This is the bean we’re going to test, it’s a simple bean with some read and write methods.

@Stateless
public class PersonBean {

	@PersistenceContext
	private EntityManager em;

	public Person findPerson(long id) {
		return em.find(Person.class, id);
	}

	public void save(Person p) {
		em.persist(p);
	}

	public List findAll() {
		return em.createNamedQuery(Person.QUERYNAME_GET_ALL_PERSONS, Person.class).getResultList();
	}
}

Setup persistence in production using MySQL and jndi

For production I’ve configured my MySQL database in glassfish using jdni. (When you don’t know how to do this, take a look at this blog post)

This is my persistence.xml in /src/main/resources/META-INF

<?xml version="1.0" encoding="UTF-8"?>
<persistence 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_2_0.xsd"
             version="2.0">
	<persistence-unit name="example" transaction-type="JTA">
		<jta-data-source>example</jta-data-source>
		<class>be.stijn.example.domain.Person</class>
		<properties>
			<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
            <property name="eclipselink.logging.level" value="ALL"/> <!-- ALL  -->
		</properties>
	</persistence-unit>
</persistence>

Setup persistence in test using Derby with jndi

This is very important!
To setup a derbyDb using the same jndi name as your production environment you’ll need to create an arquillian.xml and glassfish-resources.xml under /src/test/resources/

arquillian.xml

<?xml version="1.0" encoding="UTF-8"?>
<arquillian xmlns="http://jboss.com/arquillian" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
	<engine>
		<property name="deploymentExportPath">target/arquillian</property>
	</engine>
	<container default="true" qualifier="glassfish">
		<configuration>
			<property name="sunResourcesXml">src/test/resources/glassfish-resources.xml
			</property>
		</configuration>
	</container>
	<extension qualifier="persistence">
		<property name="defaultDataSource">jdbc/example</property>
	</extension>
</arquillian>

glassfish-resources.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
	<jdbc-connection-pool name="jdbc/example-pool"
		res-type="javax.sql.DataSource" datasource-classname="org.apache.derby.jdbc.EmbeddedDataSource"
		ping="true">
		<property name="ConnectionAttributes" value="create=true" />
		<property name="DatabaseName" value="./target/derbydb" />
		<property name="Password" value="" />
		<property name="User" value="" />
	</jdbc-connection-pool>
	<jdbc-resource jndi-name="jdbc/example" pool-name="jdbc/example-pool" />
</resources>

And finally you’ll have to create a persistence.xml in /src/test/resources/META-INF:

<?xml version="1.0" encoding="UTF-8"?>
<persistence 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_2_0.xsd"
             version="2.0">
	<persistence-unit name="example" transaction-type="JTA">
		<jta-data-source>jdbc/example</jta-data-source>
		<class>be.stijn.example.domain.Person</class>
		<properties>
			<property name="eclipselink.target-database" value="DERBY"/>
            <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
            <property name="eclipselink.logging.level" value="ALL"/>
		</properties>
	</persistence-unit>
</persistence>

Create the test

@RunWith(Arquillian.class)
@PersistenceTest
@Transactional(TransactionMode.ROLLBACK)
public class PersonBeanIntegrationTest {

}

Create a deployment method who will be called by Arquillian and who creates a archive similar to a war file but it only contains the file who are needed to run your test.

	@Deployment
	public static JavaArchive createTestArchive() {
		return ShrinkWrap.create(JavaArchive.class, "test.jar") // Create jar
				.addPackage(Person.class.getPackage()) // Add classes
				.addPackage(PersonBean.class.getPackage()) // Add more classes
				// FEST Assert is not part of Arquillian JUnit
				.addPackages(true, "org.fest")
				// .addClasses(Person.class, PersonBean.class) is an alternative
				// for addPackage
				.addAsManifestResource(EmptyAsset.INSTANCE, ArchivePaths.create("beans.xml")) // b
				.addAsResource("META-INF/persistence.xml");
	}

We are going to add an xml file with test data in /src/test/resources/datasets/. This is our initial dataset PersonBeanIntegrationTest.xml, I’m using DBUnit’s xml format but you can also do this in JSON or other formats.

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
	<person id="1" firstname="foo" lastname="bar" />
	<person id="2" firstname="duke" lastname="java" />
</dataset>

Now we can create some tests methods:

	@Test
	@UsingDataSet("dataset/PersonBeanIntegrationTest.xml")
	public void findPersonbyId() {
		Person result = personBean.findPerson(1L);

		assertEquals("foo", result.getFirstName());
		assertEquals("bar", result.getLastName());
	}

	@Test
	@UsingDataSet("dataset/PersonBeanIntegrationTest.xml")
	public void findAll() {
		List result = personBean.findAll();

		assertEquals(2, result.size());
		assertEquals("foo", result.get(0).getFirstName());
		assertEquals("bar", result.get(0).getLastName());
		assertEquals("duke", result.get(1).getFirstName());
		assertEquals("java", result.get(1).getLastName());
	}

We can also assert the expected dataset after a test method, so we create datasets\PersonBeanIntegrationTest_save.xml in src\test\resources.

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
	<person id="1" firstname="foo" lastname="bar" />
	<person id="2" firstname="duke" lastname="java" />
	<person id="3" firstname="firstname" lastname="lastname" />
</dataset>

And finally the save test method:

	@Test
	@UsingDataSet("dataset/PersonBeanIntegrationTest.xml")
	@ShouldMatchDataSet("dataset/PersonBeanIntegrationTest_save.xml")
	@Transactional(TransactionMode.COMMIT)
	public void save() {
		Person p = new Person();
		p.setFirstName("firstname");
		p.setLastName("lastname");

		personBean.save(p);

	}

To view the entire source code look over here.

Update:
You can configure dbunit inside arquillian.xml take a look.

About these ads