Technology with opinion

Monday, February 15, 2010

Unit Testing Daos with NHibernate with SessionScopes Version 2

In a previous post I outlined how to modify Ayende's post to support contextual sessions. With Contextual Sessions in NHibernate instead of injecting a Session into each DAO you will be injecting a SessionFactory in which the caller will invoke the SessionFactory's GetCurrentSession() in order to get the session tied to the context. The previous example I mocked the SessionFactory and stubbed the GetCurrentSession() to return one session that would have been open for the life of a TestFixture.

This really isn't necessary if you bind the SessionFactory to a context. This is very easy with NHibernate and the only requirement is that you tell NHibernate through it's configuration the scope of your session context.

Something else I've thought about was that each TestFixture should only every test one DAO. The tests in said fixture should also only ever reference one DAO to be an independent test. Therefore if you are testing and a function from your DAO and need another object from persistence it would be better to call get the persisted object directly from your Session than from a separate DAO. Too often I see people trying to reuse objects in their Unit Tests which violates the integrity of the tests because they would no longer be independent.

Therefore it would be nice if the InMemoryDatabaseTest exposed the target DAO to the TestFixture to make it easier, it could also set the SessionFactory of the DAO. We can do this easily with Generics:

I have extended my existing base test fixture InMemoryDatabaseTest so that I don't break compatability with existing tests. All my new DAO TestFixtures will inherit from the new Generic version. I have also added some overloads for debugging. If you pass a true debug flag to the constructor it will output the SQL to the output Window. Also you can pass in a path to an actual SQLite file/db which will let you save the changes. This is helpful for complicated tests where you want to see what is being saved to the database and test the queries NHibernate is executing against SQLite.

BaseDao that all your DAOs inherit from to facilitate contextual sessions. This code should be in a separate assembly I call (rootnamespace).Data.Common InMemoryDatabaseTest that your test fixtures would inherit from. This code should be in a separate assmebly I call (rootnamespace).Testing.Common Usage

As you can see, the DAOs Unit Test didn't have to instantiate an instance of the target DAO since it already specified it as a Generic paramter. While this only eliminates 2 lines of code it more importantly enforces one DAO per test.