Testing JPA 1.x with OpenEJB Embedded 3.1
dan.j.allen Oct 2, 2010 1:35 PMI figured out how to test a JPA 1.x application using OpenJPA 1.2 and the OpenEJB Embedded 3.1 container adapter. The benefit is that it's fast, fast, fast!
I haven't been able to get JPA 2.x to work since it's not supported in the release version of OpenEJB (3.1.2). I've heard, though, that support is just around the corner.
The trickiest part of testing JPA is configurating a test DataSource. Fortunately, this is very easy to do in OpenEJB. Just create a jndi.properties file on the classpath (in src/test/resources if you are using Maven) and populate it with these properties:
java.naming.factory.initial=org.apache.openejb.client.LocalInitialContextFactory testDatabase=new://Resource?type=DataSource testDatabase.JdbcDriver=org.hsqldb.jdbcDriver testDatabase.JdbcUrl=jdbc:hsqldb:mem:testdb testDatabase.JtaManaged=true
Of course you would change "testDatabase" and "testdb" to whatever you want to call your embedded database. HSQLDB is on the classpath by default when using OpenEJB. If you want to use another driver, just include the appropriate JAR on the classpath and update the JdbcDriver property.
Eventually you'll be able to configure your JNDI properties in arquillian.xml (I hope)
Next, you'll create a test-persistence.xml file on the classpath (in src/test/resources if you are using Maven) that initializes a database using this DataSource:
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.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="test"> <jta-data-source>testDatabase</jta-data-source> <properties> <!-- configures OpenJPA to generate the database schema automatically --> <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/> <!-- print SQL being executed --> <property name="openjpa.Log" value="DefaultLevel=WARN, SQL=TRACE"/> </properties> </persistence-unit> </persistence>
OpenJPA will fail to load if you forget to put one of the entity classes in the ShrinkWrap archive, so don't forget!
Now you can simply inject an EntityManager into a session bean and use it. Since this is an EJB, all transactions are handled for you automatically.
@Stateless @Local(PersistenceService.class) public class PersistenceServiceBean { @PersistenceContext private EntityManager em; public void seed() { em.persist(new Record("Sample record")); } public List<Record> selectAll() { return em.createQuery("select r from Record r").getResultList(); } }
Here's an example of an Arquillian test that invokes this service (in a real EJB environment!)
@RunWith(Arquillian.class) public class PersistenceServiceTestCase { @Deployment public static Archive<?> createDeployment() { return ShrinkWrap.create(JavaArchive.class) .addClasses(Record.class, PersistenceService.class, PersistenceServiceBean.class) .addManifestResource("test-persistence.xml", "persistence.xml"); } @EJB PersistenceService service; @Test public void queryShouldFindSeedRecord() { service.seed(); List<Record> results = service.selectAll(); assertEquals("Should have found one record", 1, results.size()); } }
Lately, we need to setup the dependencies needed to execute Arquillian. Here's an example of Maven profile that's active by default:
<profile> <id>arq-openejb-embedded</id> <activation> <activeByDefault>true</activeByDefault> </activation> <dependencies> <dependency> <groupId>org.jboss.arquillian.container</groupId> <artifactId>arquillian-openejb-embedded-3.1</artifactId> <version>1.0.0.Alpha4</version> </dependency> <dependency> <groupId>org.apache.openejb</groupId> <artifactId>openejb-core</artifactId> <version>3.1.2</version> </dependency> <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency> </dependencies> </profile>
If you are testing with other containers, you'll want to put the OpenEJB resources (jndi.properties and test-persistence.xml) in their own resource directory (e.g., src/test/resources-openejb-embedded) and include that as a resource directory in the profile. See the Arquillian showcase for examples of this configuration.
Have fun testing those mappings!