Wednesday, April 13, 2011

Hibernate - Part 4 - Testing persistence code with JUnit

I'd like to preface this post by saying this is not intended to be a best practice for testing Hibernate related application code.  I'd just like to show the methodology I'm using at the moment and discuss a few of the call outs I've found on this topic.  Of course, reader input and suggestions are always encouraged so please feel free to fire away.

In a previous post, I discussed the Hibernate mappings file and Ant tasks I'm using to create my Java entity classes and database tables.  I've since created some classes that wrap the CRUD functions for these entities.  I'll refer to these as my persistence classes. Of course these classes use the Hibernate framework (Transaction, Session, Query) and also have a little logic for dealing with the underlying relationship between the entities.

So now I need to test the code.  Yes I know, ideally I'd have written the tests before writing my persistence classes.  :)  I'm using JUnit for unit testing and since both JUnit and Hibernate are quite popular I figured I could quickly locate some online examples of using the two together.  Well, here's where things get a little complicated, or should I say controversial...

First off, I should probably refer to the testing of my persistence classes as integration testing and not unit testing.  As this Stack Overflow post explains, a unit test "should be a stand-alone test which is not related to other resources" and the integration test is "similar to unit tests but with external resources (db, disk access)".

Putting aside the semantics, what's the best way to use JUnit to test your Hibernate related code?  Here are some of the suggestions I've found:
  • Don't do a straight test of Hibernate related code with JUnit, use Spring instead.  Spring has a testing module for writing unit and integration tests.
  • Mock the Hibernate layer by using a mocking framework like JMock.  This enables you to focus your unit test on your code and removes any external frameworks (ie. Hibernate) from the test.
  • Use JUnit extension DbUnit to put your database into a known state before test runs.
  • Use an embedded, in-memory, database like HSQL for your testing.  This removes the reliance on your external full-fledged RDMS.
I'm eager to use Spring but it's not going to happen with this project or at least this phase of the project.  I'd also like to try the mocking or DbUnit approach, and I may do so but it won't happen until later either.

For reference, here's a couple of forum posts where JUnit and Hibernate are discussed:

For now, I'm going against better judgement and testing my persistence code with straight JUnit tests against my MySQL database.  I'll test the CRUD functions of my persistence classes and leave it at that.

I've created a JUnit test class for each of my persistence classes.  Rather than creating a Hibernate SessionFactory with each test method, I'll create it once in the JUnit @BeforeClass method and close it in the @AfterClass method.  Here's what it looks like along with one of the test methods:
    @BeforeClass
    public static void oneTimeSetup() throws Exception  {
        logger.debug("Entering oneTimeSetup()");
       
        // A SessionFactory is set up once for an application
        sessionFactory = new Configuration()
                .configure() // configures settings from hibernate.cfg.xml
                .buildSessionFactory();
    }
   
    @AfterClass
    public static void oneTimeTearDown() {
        logger.debug("Entering oneTimeTearDown()");
       
        if ( sessionFactory != null ) {
            sessionFactory.close();
        }
    }
   
    @Test
    public void testCreateTag() {
        logger.debug("Enter testCreateTag()");
       
        // create new Tag object
        Tag tag = new Tag("tag1");
       
        TagPersister tagPersister = new TagPersister();
       
        // Ask for a session using the JDBC information we've configured
        Session session = sessionFactory.openSession();
       
        assertTrue("Error while creating new Tag", tagPersister.createTag(tag, session));
    }
What do you think?  Reader ideas and suggestions are encouraged and appreciated.

    1 comment: