No AUTO COMMIT in Unit test for Hibernate with JPA annotation

5k views Asked by At

I'm trying to create a unit test for my persistence code. I'm using Hibernate with JPA annotations. I do not have persistence.xml (which is used in all articles about JPA unit testing). I do not want to use spring or create persistence.xml because I have many persistence classes and initialization of hibernate for all of them takes a lot of time, so I want to add classes to hibernate explicitly.

Also I can't use configuration.createSessionFactory() as it is recommended in Hibernate unit test articles, because my DAOs has JPA EntityManager injected by Spring.

So I'm using EntityManagerFactoryImpl:

AnnotationConfiguration configuration = new AnnotationConfiguration();

configuration.setProperty(Environment.DRIVER,"org.apache.derby.jdbc.EmbeddedDriver");
configuration.setProperty(Environment.URL,"jdbc:derby:memory:srf.derby;create=true");
configuration.setProperty(Environment.USER, "");
configuration.setProperty(Environment.DIALECT, DerbyDialect.class.getName());
configuration.setProperty(Environment.SHOW_SQL, "true");
configuration.setProperty(Environment.HBM2DDL_AUTO, "create-drop");
configuration.setProperty( Environment.AUTOCOMMIT, "true");

configuration.addAnnotatedClass(MyPersistentClass.class);

MyHibernateDAO dao = new MyHibernateDAO();

EntityManagerFactoryImpl entityManagerFactory = new EntityManagerFactoryImpl(
                                  configuration.buildSessionFactory(),
                                  PersistenceUnitTransactionType.RESOURCE_LOCAL, 
                                  true, 
                                  null, 
                                  configuration);

dao.setEntityManager(entityManagerFactory.createEntityManager());

This looks okay, but from some reason no any insert fired to db, while all selects are okay (I have show SQL true). It looks like AUTOCOMMIT is false (in production world Spring manages transactions). As you see I set configuration to AUTOCOMMIT true, I even retrive JDBC connection from EntityManager and I see in debugger, that autocommit is true, but inserts are fired only if in my unit test I explicitly begin and commit transaction.

What I'm doing wrong? How can I make my test running in autocommit?

Thank you!

1

There are 1 answers

6
esaj On

I assume you are using @Transactional-annotations in your DAO-code. The problem is, as you instantiate your EntityManager and DAO by hand, there's no TransactionManager or proxies to take care of reacting to those annotations, so a transaction is never created automatically.

If you really want to commit data to your database in tests without creating the Spring ApplicationContext or without using Springs' JUnit-runners etc, I believe you need to handle the transactions yourself (could be wrong though). Easiest way would probably be to create a baseclass from which to extend your tests, something like:

import javax.persistence.EntityManager;

import org.hibernate.cfg.AnnotationConfiguration;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;

public abstract class TransactionalTestBase
{
    private EntityManager em;

    protected abstract Class<?>[] getAnnotatedClasses();

    @BeforeClass
    public void setupEntityManager()
    {
        //Build your basic configuration

        AnnotationConfiguration configuration = new AnnotationConfiguration();
        //configuration.setProperty(
        //...

        //Ask the implementing class for the entity-classes
        for(Class<?> clazz : getAnnotatedClasses())
        {
            configuration.addAnnotatedClass(clazz);
        }

        //Set up your entitymanager here

    }

    @Before
    public void beforeTest()
    {
        em.getTransaction().begin();
    }

    @After
    public void afterTest()
    {
        if(em.getTransaction().getRollbackOnly())
        {
            em.getTransaction().rollback();
        }
        else
        {
            em.getTransaction().commit();
        }
    }

    @AfterClass
    public void tearDownEntityManager()
    {
        em.flush();
        em.clear();
        em.close();
        em = null;
    }
}

Note that as you extend further classes from this, you can add more @BeforeClass, @Before etc. -annotations, they will be run in inheritance order.

If you decide to leverage Spring with your testing, see http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/testing.html