Unit test JPA Entities with in-memory database
Still about Hibernate, I have several JPA Entities grouped in a Persistence Unit that I need to test. So here is another quick and dirty howto titled “Unit test JPA Entities with in-memory database”.
Here I assume you already have written your entities java classes with correct annotations.
As I’m working with embedded Derby for a year, I first tried with it but procton (thank you procton) pointed me to another lightweight RDBMS.
So, in this how-to we will set up a unit-tests dedicated persistence unit and use HSQLDB as in-memory database for unit tests.
Dependencies
I won’t mess with classpath issues here because I’m extensively using maven and … I don’t mess with simple classpath issues anymore
<subliminal>use maven, use maven, use maven, it’s a good piece of software</subliminal>
Here are the dependencies I added to my project with the “test” scope :
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>3.3.1.ga</version> <scope>test</scope> </dependency> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>1.8.0.7</version> <scope>test</scope> </dependency>
I needed the hibernate-entitymanager as it’s a project with only entity classes in it.
Persistence Unit
Here the interesting snippet of my META-INF/persistence.xml file :
<persistence-unit name="testPU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>myapp.model.entities.Group</class>
<class>myapp.model.entities.User</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.connection.url" value="jdbc:hsqldb:mem:unit-testing-jpa"/>
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.connection.username" value="sa"/>
<property name="hibernate.connection.password" value=""/>
</properties>
</persistence-unit>
It’s only a snippet because I have several persistance-unit nodes, one for production, one for development, one for unit testing.
The unit test
I’m still using JUnit 3 but if you’re using the 4th version, you won’t be lost. Here is a simple complete test case :
public class PersistenceUnitTest extends TestCase {
private static Logger logger = Logger.getLogger(PersistenceUnitTest.class.getName());
private EntityManagerFactory emFactory;
private EntityManager em;
private Connection connection;
public PersistenceUnitTest(String testName) {
super(testName);
}
@Override
protected void setUp() throws Exception {
super.setUp();
try {
logger.info("Starting in-memory HSQL database for unit tests");
Class.forName("org.hsqldb.jdbcDriver");
connection = DriverManager.getConnection("jdbc:hsqldb:mem:unit-testing-jpa", "sa", "");
} catch (Exception ex) {
ex.printStackTrace();
fail("Exception during HSQL database startup.");
}
try {
logger.info("Building JPA EntityManager for unit tests");
emFactory = Persistence.createEntityManagerFactory("testPU");
em = emFactory.createEntityManager();
} catch (Exception ex) {
ex.printStackTrace();
fail("Exception during JPA EntityManager instanciation.");
}
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
logger.info("Shuting down Hibernate JPA layer.");
if (em != null) {
em.close();
}
if (emFactory != null) {
emFactory.close();
}
logger.info("Stopping in-memory HSQL database.");
try {
connection.createStatement().execute("SHUTDOWN");
} catch (Exception ex) {}
}
public void testPersistence() {
try {
em.getTransaction().begin();
User u = new User();
u.setEmail("eskatos@yopmail.com");
u.setFirstName("eskatos");
u.setLastName("YOP");
u.setOrganisation("Tagada");
em.persist(u);
assertTrue(em.contains(u));
Group g = new Group();
g1.addUser(u);
em.persist(g);
assertTrue(em.contains(g));
g.removeUser(u);
em.remove(u);
em.merge(g);
assertFalse(em.contains(u));
em.getTransaction().commit();
} catch (Exception ex) {
em.getTransaction().rollback();
ex.printStackTrace();
fail("Exception during testPersistence");
}
}
}
Et voila !
Thanks for information.
many interesting things
Celpjefscylc
Hi,
thanks for you article. I am doing the same type of testing but can’t figure out how to do testing and deployment using a single persistence.xml. The problem is when I deploy into jboss it doesn’t like the unit testing persitence context being defined because it’s resource-local. I am interested to know if you have faced similar issue and how you solved the pb.
thanks
andre
Hi Andre,
I do not have this issue. Using Hibernate in GlassFish here.
Now I’m using separate persistence.xml files and my build tool (maven) allows me to change the persistence.xml file used during unit tests.
It’s no solution but I hope this helps.
Paul
Hey Paul,
Thanks for the reply. I guess using the build tool to select the appropriate file is really the way to go.
In the mean time i have noticed that Jboss complains about seeing a “resouce-local” persistence context but deploys everything ok. So for the moment i am living with the error and will get to modifying my ant script shortly.
thanks
andre
Tried this out just now. Using Maven, too and practically followed your example to the letter but am getting “java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/persistence/Persistence”.
Any ideas? Do I have to add the Glassfish runtime libraries (or in my case, JBoss) to the classpath via Maven dependencies, too (not covered in your post)?
@Alistair : I didn’t have to add GF runtime as test dependencies. The error you get sounds weird. Is your project aimed at java 5+ ?