Eskatos’s thoughts on JEE development

Unit test JPA Entities with in-memory database

Posted in HOWTOs by eskatos on October 15th, 2007

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 !

Tagged with: , , ,

6 Responses to 'Unit test JPA Entities with in-memory database'

Subscribe to comments with RSS or TrackBack to 'Unit test JPA Entities with in-memory database'.

  1. celpjefscycle said, on January 12th, 2008 at 9:32 am

    Thanks for information.
    many interesting things
    Celpjefscylc

  2. andre said, on January 17th, 2008 at 3:52 pm

    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

  3. eskatos said, on January 22nd, 2008 at 7:49 pm

    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

  4. andre said, on January 24th, 2008 at 1:45 pm

    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

  5. Alistair said, on May 2nd, 2008 at 10:23 am

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

  6. eskatos said, on May 2nd, 2008 at 1:29 pm

    @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+ ?

Leave a Reply