Dave
Dave

Reputation: 19340

Hibernate: how to roll back transactions after a JUnit test?

I'm using Hibernate 4.0.1.Final within a standalone application. The underlying db is MySQL 5.5. Using JUnit 4.8.1, I'm testing my data access object, and would like to run tests so that when my JUnit test ends, all my changes are rolled back. Is there an elegant way to do that? Right now, everything is being committed, which makes sense. Here's my JUnit test …

@Before
public void setUp() throws IOException { 
    final InputStream in = getClass().getClassLoader().getResourceAsStream("test.properties");
    testProps = new Properties();
    testProps.load(in);
    final Configuration configuration = new Configuration();
    configuration.configure().setProperty("hibernate.show_sql", "false");
    final ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
    sessionFactory = configuration.buildSessionFactory(serviceRegistry);
    orgDao = new OrganizationDAOImpl(sessionFactory);
}   // setUp

@Test
public void testInsertSchool() { 
    final Organization org = new Organization();
    org.setOrganizationId(testProps.getProperty("test.id"));
    org.setName(testProps.getProperty("test.name"));
    orgDao.saveOrUpdate(org);
    final Organization foundOrg = orgDao.findById(org.getOrganizationId());
    Assert.assertEquals(org, foundOrg);
}

Here's the code from the data access object …

protected void saveOrUpdate(Object obj) {
    try {
        startOperation();
        session.saveOrUpdate(obj);
        tx.commit();
    } catch (HibernateException e) {
        handleException(e);
    } finally {
        session.close();
    }
}

protected Object find(Class clazz, Serializable id) {
    Object obj = null;
    try {
        startOperation();
        obj = session.get(clazz, id);
        tx.commit();
    } catch (HibernateException e) {
        handleException(e);
    } finally {
        session.close();
    }
    return obj;
}

Upvotes: 1

Views: 1602

Answers (2)

Dave
Dave

Reputation: 19340

What I decided to do was use a HSSql in-memory database, as described here -- http://vageeshhoskere.wordpress.com/2011/06/16/unit-test-with-junit-for-hibernate-using-hsqldb-in-memory/ . That way, I can repeatedly run JUnit tests (at the service level) and be guaranteed the state of the world will be the same each time I run them.

Upvotes: 1

hsanders
hsanders

Reputation: 1898

The way to do that would be to separate out your commits and session closes from your database operations. I actually think it's better to do that anyhow because not every database operation should be its own transaction. There are significant advantages to being able to use the same session in multiple operations and to use the same transaction for multiple operations.

The way I'd characterize the transaction layer is it's a business rule concern, as they define atomic units of work at the database level. It ought to be one layer out from the layer that abstracts hibernate operations for persist, find, and merge. Heres why:

  1. Doing this will allow a lot greater flexibility in how you design your application's business rules to handle new cases in which different database operations are interdependent without forcing you to write a million methods in that database object just to handle the different transaction rules for each case.
  2. Not only that, moving those operations out allows you to achieve what you want in your unit tests.
  3. Open/Close operations are expensive, if you're doing 5 queries in a row and there's no reason for them to be in a separate session, you shouldn't be opening and closing 5 sessions.

Upvotes: 0

Related Questions