timmorrow wrote:
* We use Spring's
AbstractTransactionalSpringContextTests as our base test class. This ensures your tests run in a transaction. Furthermore it always rolls back at the end of the test. So in actuality you can delete all data from all tables (they provide a convenience method to do this) before running your tests. Spring then rolls-back (including your deletes). Bonus: it also can autowire your DAO/Manager classes into the test. It also ensures that the ApplicationContext is initialized only once for all test methods, rather than once per test.
In my case, I’ve tried to eliminate the ties between my Hibernate code and Spring. Since I have plans for at least one application that will not be Spring based, I want to make sure I’m not muddying the waters.
timmorrow wrote:
* You are right that setting up test data using the same classes you are testing does seem a little "dirty". You could use DBUnit to completely separate the test setup. Or you could use the Hibernate Session methods directly. However, in practice, we do use the DAO/Manager methods to setup our test data.
I appreciate the pointer to DBUnit. I am reviewing the package now and think it might work out fairly well. Firing out a bunch of SQL before/after the test was what I was thinking, but really wanted to find a way to automate it as well. This should work nicely!
timmorrow wrote:
* If you do happen to use other methods to setup your test data, don't assume that means you can skip testing those methods directly. For example, while you might call createPerson() and getPersonById() before testing update, you won't have tested all facets of those methods. You'll want to test getPersonById() with an existing and non-existing PK. You'll want to test createPerson() with and without not null fields filled in.
You make a very good point here that I didn’t think about… While the data being passed between routines is fairly predictable, the data being passed directly into the methods from outside code (i.e my applications) might not be. So error conditions I address in the other routines won’t show up as they would if I were randomly calling methods. Good advice!
timmorrow wrote:
* If you are going to be setting up your test data using Hibernate and within the same transaction as the tests themselves you should be sure to call flush() and clear() on the session after setting up the data. This ensures the SQL is really executed and the Session-cache is cleared. Otherwise, your tests might not even generate any SQL or hit the database.
* I also recommend executing flush() and clear() before verifying the results of your test for the same reason.
Being a Hibernate newbie, I wasn’t sure if I should do that or not. I had planned to do so (just to make sure), so your recommendation makes me feel a little better. Thanks!
timmorrow wrote:
* In terms of verification: while checking all fields of the object would be ideal, in practice I'd just test for equality. If during persistence you manipulate certain fields (like inserting timestamps etc.) you'd want to check those too. Checking the PK is almost certainly not enough because often that value is filled in even if a load fails - you must access another field on the object to cause Hibernate to throw an exception.
That’s what I figured as well. Thanks!
timmorrow wrote:
* Finally, if you're going to be sharing these DAO classes with other apps, create something like a dao-beans.xml with all DAOs defined with a dependency on a SessionFactory bean that you _don't_ provide. The other users of your library will then get the bean definitions for free - they simply have to ensure they have their correct SessionFactory available in the application context with the appropriate bean name.
I’m not familiar with dao-beans.xml you are referring to… Can you give a pointer to this? I’m including the Hibernate XML mappings in the JAR file, is this what you mean?
All in all, I appreciate the response! It contains a bunch of good advice and makes me feel a bit better about the direction I’m heading in! Thank you very much!