eskatos's thoughts

Unit test JPA Entities with in-memory Derby/JavaDB

with 7 comments

HibernateAbout two years ago I blogged about using HSQLDB to unit test JPA entities. This year, Apache released a Derby version allowing you to use an in memory backend. As I use Derby in software I write, being able to run unit tests on the very same SGBD but in memory is a real gift.

For reference, here is a link to my previous post titled Unit test JPA Entities with in-memory database. What follows is just the very same method applied to Derby.


Dependencies

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.2.GA</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.apache.derby</groupId>
    <artifactId>derby</artifactId>
    <version>10.5.3.0</version>
    <scope>test</scope>
</dependency>

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:derby:memory:unit-testing-jpa"/>
        <property name="hibernate.connection.driver_class" value="org.apache.derby.jdbc.EmbeddedDriver"/>
        <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect"/>
        <property name="hibernate.hbm2ddl.auto" value="create"/>
        <property name="hibernate.connection.username" value=""/>
        <property name="hibernate.connection.password" value=""/>
    </properties>
</persistence-unit>

The unit test

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;

    public PersistenceUnitTest(String testName) {
        super(testName);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        try {
            logger.info("Starting in-memory database for unit tests");
            Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
            DriverManager.getConnection("jdbc:derby:memory:unit-testing-jpa;create=true").close();
        } catch (Exception ex) {
            ex.printStackTrace();
            fail("Exception during 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 database.");
        try {
            DriverManager.getConnection("jdbc:derby:memory:unit-testing-jpa;shutdown=true").close();
        } catch (SQLNonTransientConnectionException ex) {
            if (ex.getErrorCode() != 45000) {
                throw ex;
            }
            // Shutdown success
        }
        VFMemoryStorageFactory.purgeDatabase(new File("unit-testing-jpa").getCanonicalPath());
    }

    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, now with Derby :) !

Advertisement

Written by eskatos

October 26, 2009 at 5:52 pm

Posted in Code, HOWTOs

Tagged with , , ,

7 Responses

Subscribe to comments with RSS.

  1. [...] UPDATE: now that Apache Derby provide an in memory backend, I implemented the very same thing with it in a new post : Unit test JPA Entities with in-memory Derby/JavaDB [...]

  2. Thanks for the information, eskatos.
    Great to see the in-memory back end being used :)

    I just want to point out that the way to delete Derby / Java DB in-memory databases (and possibly other types of databases) will change in the next feature release. The current mechanism I’m looking into is using a connection URL property, like “jdbc:derby:memory;mydb;delete=true[;user=...;password=...]“.

    If anyone has feedback on the current implementation or wishes for future features, feel free to share it with the community on the Apache Derby user’s mailing list. The in-memory database back end in Derby 10.5 is considered experimental, so this is the time to raise your opinion if you want to see major compatibility breaking changes!

    Regards,

    Kristian Waagan

    October 27, 2009 at 6:17 pm

  3. Great post! I have a question, though. I am planning to use it for unit testing seam ejb using maven. Where do I put META-INF/persistence.xml file? Under \test\resources directory? Thank you in advance.

    Brian Ko

    January 16, 2010 at 2:15 am

  4. Hi,

    I did exactly the same with Derby for inmemory testing and encapsulated it into a framework. The framework allows inmemory testing as well as connecting to a third-party framework.

    Have a look at http://utils.wamblee.org/test/enterprise/index.html, and in particular at http://utils.wamblee.org/test/enterprise/apidocs/org/wamblee/test/persistence/package-summary.html

    I am developing this as open source and it is available on the central maven repo.

    Cheers
    Erik

    Erik Brakkee

    July 19, 2010 at 12:40 am

    • correction: “connection to a third-party framework” should be “connecting to an external database”.

      Erik Brakkee

      July 19, 2010 at 12:41 am

  5. [...] Configuración de JPA para usar Hibernate [...]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.