views:

58

answers:

2

We have an application built using spring/Hibernate/MySQL, now we want to test the DAO layer, but here are a few shortcomings we face.

Consider the use case of multiple objects connected to one another, eg: Book has Pages.

  • The Page object cannot exist without the Book as book_id is mandatory FK in Page.
  • For testing a Page I have to create a Book.

This simple usecase is easy to manage, but if you start building a Library, till you don't create the whole universe surrounding the Book and Page, you cannot test it!

So to test Page;

  • Create Library
  • Create Section
  • Create Genre
  • Create Author
  • Create Book
  • Create Page
  • Now test Page.

Is there an easy way to by pass this "universe creation" and just test the page object in isolation. I also want to be able to test HQLs related to Page. eg:

SELECT new com.test.BookPage (book.id, page.name) FROM Book book, Page page.

JUnit is supposed to run in isolation, so I have to write the code to build all the supporting objects in the test case to create the Page. Any tips on how to accelerate the process.

Edit: Spring follows the philosophy of transaction roll-back after the tests have been run, thereyby reverting all changes. Schema changes are expected as we develop further, I want to be able to test it against the production db (backup!) on a regular basis.

+3  A: 

I just finished a project with this exact configuration. We had great success using a stand-in HSQLDB database for the unit tests and then turning off referential integrity on the schema for those tests.

Since you're using Spring, these are the steps:

  1. Create a new context configuration file for testing. Set up hibernate to do create-drop for the schema in this configuration.
  2. Create your junit test. Inherit from AbstractTransactionalJUnit4SpringContextTests, the greatest abstract class in the history of the universe, and annotate the class with your new @ContextConfiguration. Also use the @TransactionConfiguration annotation to run each test in a transaction with an automatic rollback.
  3. run the command "SET REFERENTIAL_INTEGRITY FALSE;" through the inherited simpleJdbcTemplate property in your @Before method.
  4. dedicate the rest of the @Before to simpleJdbcTemplate calls that set up the database. Note that you no longer need to specify every referenced column, just what you're testing!
  5. Finally write your unit tests against your DAO's.

Here's a few references that will get you moving in this direction:

As usual with this stuff, getting the config just right is the hard part. But once it's all working, you'll be a styling unit tester!

roufamatic
I'm not comfortable turning off referential integrity even for testing.
Varun Mehta
To each his own. I found that from a unit test perspective my test fixture was cut in half when I removed referential integrity. Since I was only interested in testing the HQL queries, not the DB schema configuration, it worked very well. Additionally since it's a totally different database system -- in memory, at that -- there's no worry about corrupting any production data.
roufamatic
We don't let hibernate generate the schema, we just map the object to SQL, and run hbm2ddl validation to make sure it conforms the standard. We also want to make sure the schema configuration is proper, it's a part of the testing phase.
Varun Mehta
A: 

The Unitils extensions to junit or testng have very nice support for this. They allow you to define datasets tuned for your class under test so it only needs the part of the universe your class is seeing and then it initializes the database before the tests start.

checkout : link text

We are using it and it just works fine. A lot better that the "MockRepositories" which we used before which do not test the HQL and, also important, the hibernate transaction behaviors.

Peter Tillemans
Unitils looks promising, let me explore it more and get back to you.
Varun Mehta
Unitils offers more than just the database stuff, e.g. lenient collection matchers. It is a good thing to have in your tool belt.
Peter Tillemans