One of the things that is always a pain when unit testing is when you need to test functionality that utilizes persistence. The unit tests that are easy are the ones that just test the functionality in your POJOs that doesn’t require persistence to test. Then there are the tests you want to write to make sure that your persistence configuration is correct. For example, you want to make sure that you’ve got your associations in Hibernate configured properly or that changes to data model don’t break things when you go to save. I’ve made mistakes before where I added a property that was required but some of my code didn’t set that property. It’d be nice to know that by having a unit test tell me that saving the object fails in certain situations.
The difficult part in this is getting a database configured. No one really wants to have one or more databases that are just for testing. It’s a pain to maintain and is going to be slow. When you unit test most times you are going to want to start with a clean slate and then populate with the data that is necessary for your tests. All of this overhead for a test? Not Ideal. What are some options?
Hypersonic is a Java database that can be run either on disk or in-memory. The in-memory is what we’re most interested in for testing because it doesn’t require a location on disk to run, is extremely fast since it doesn’t require disk access and is compact.
What I do is have a separate hibernate.cfg.xml file for unit testing that is identical in most regards to my production hibernate.cfg.xml except for the fact that it uses a straight JDBC connection vs. a DataSource reference for its connection source. Additionally, I tell Hibernate to create the database schema upon startup. Here is an example of some of the entries I set:
<property name="hibernate.connection.url"> jdbc:hsqldb:mem:testdb </property> <property name="hibernate.connection.driver_class> org.hsqldb.jdbcDriver </property> <property name="hibernate.dialect> org.hibernate.dialect.HSQLDialect </property> <property name="hibernate.connection.provider.class> org.hibernate.connection.DriverManagerConnectionProvider </property> <property name="hibernate.hbm2ddl.auto> create-drop </property>
The key here is the JDBC url, jdbc:hsqldb:mem:testdb, which tells Hypersonic to run in-memory vs. on disk and then the setting for hibernate.hbm2ddl which is create-drop and tells Hibernate to perform automatic schema generation.
I also use Spring as my primary application container/framework and so what I also do is have an applicationContext.env.xml for my normal application database environment and then a testApplicationContext.env.xml for testing. The main difference is the normal one configures the Hibernate SessionFactory with the production Hibernate configuration file and the test environment file configures it with the test Hibernate configuration. When I go to run unit tests that need both Spring and Hibernate I will use the test application context in place of the normal one. It’s pretty easy to do since I have a base class used for testing that will build out the application context during startup. It does this by just listing all of the Spring configuration files during startup and passing them in to the appropriate ApplicationContext sub-class.
Give this approach a try if you’ve been struggling with unit testing that involves database operations. It has saved me a lot of time and headache since I started using it. You can send me an e-mail if you have any questions about this.
Next up, code coverage with Emma.