Testing NHibernate Mappings

Several posts have been made lately concerning testing NHibernate Mappings. I thought I would share what I have done for the past few months.

I create a test fixture for each class mapped in NHibernate. The tests in the fixture test loading, updating, saving, and deleting through NHibernate.

Initially, I only tested loading, but later found out that when we started saving objects with NHibernate, it broke. Likewise, with deletes, I found some cascading deletes conflicted with triggers in the database (that I had no conrtol over). Had I tested the deletion, I would have known. So I find it a good practice to test all of the above for your mappings.

Here are some sample tests

[ TestMethod ]

public void Loading_a_VirtualColumn_will_populate_all_its_properties()

{

VirtualColumn expectedColumn = Anonymous.VirtualColumn();

// Insert column into Db.

_context.AddVirtualColumn( expectedColumn );

_context.Persist( _session );

// Load from Db.

VirtualColumn actualColumn = _session.Get<VirtualColumn>( expectedColumn.Id );

// Ensure all properties match.

TestAssertions.VirtualColumnEquals( expectedColumn, actualColumn );

}

[ TestMethod ]

public void Updating_a_VirtualColumns_CriteriaExpression_and_saving_should_persist_the_change()

{

VirtualColumn column = Anonymous.VirtualColumn_WithVersionCriteria();

// Insert column with its criteria expression into Db.

_context.AddVirtualColumn( column );

_context.Persist( _session );

// Get column to update from db.

VirtualColumn persistedColumn = _session.Get<VirtualColumn>( column.Id );

Assert.IsInstanceOfType( persistedColumn.CriteriaExpression,

typeof ( VersionExpression ) );

// Update column and persist.

persistedColumn.CriteriaExpression = Anonymous.BudgetYearExpression();

_session.SaveOrUpdate( persistedColumn );

_session.Flush();

// Get the updated column.

VirtualColumn actualColumn = _session.Get<VirtualColumn>( column.Id );

// Ensure the change was persisted.

Assert.IsInstanceOfType( actualColumn.CriteriaExpression,

typeof ( BudgetYearExpression ) );

}

[ TestMethod ]

public void Deleting_a_Virtual_Column_should_remove_it_from_the_db()

{

VirtualColumn column = Anonymous.VirtualColumn();

// Insert column into Db.

_context.AddVirtualColumn( column );

_context.Persist( _session );

// Get column to delete from db.

VirtualColumn persistedColumn = _session.Get<VirtualColumn>( column.Id );

// Delete the column.

_session.Delete( persistedColumn );

_session.Flush();

// Ensure it was removed from db.

TestDataAssertions.VirtualColumnDoesNotExist( column, _session );

}

[ TestMethod ]

public void Deleting_a_Virtual_Column_should_also_remove_its_Criteria_Expression_from_the_db()

{

VirtualColumn column = Anonymous.VirtualColumn_ForAmountInPeriod( January );

// Insert column into Db.

_context.AddVirtualColumn( column );

_context.Persist( _session );

// Get column to delete from db.

VirtualColumn persistedColumn = _session.Get<VirtualColumn>( column.Id );

// Delete the column.

_session.Delete( persistedColumn );

_session.Flush();

// Ensure it was removed from db.

TestDataAssertions.ExpressionDoesNotExist( column.CriteriaExpression, _session );

}

The code may require some explanation, because much of the nuts and bolts functionality is hidden behind classes that make the tests much more readable. Let me explain what these do:

The _context object is a DynamicConext class that I created for unit testing that allows me to easily create test object graphs, and it also provides the ability to insert the data from those objects into a database. It uses the NHibernate _session object to do so, but doesn’t use the NHibernate mappings.

The Anonymous object is an object mother I created to create anonymous test objects. It simply returns a valid object with random data.

The TestAssertions and TestDataAssertions classes are custom assertions I wrote to increase readability of the tests. The TestAssertions assert against objects whereas the TestDataAssertions assert against a database. This is so that I can test the database state independently from NHibernate. (It’s not a good idea to use NHibernate to test NHibernate).

Note that the tests do not use any custom repositories from my domain. They just use the NHibernate session directly. This is because I am not testing my repositories. I only want to test my NHibernate mappings. If I had a custom repository for the “CalculatedField” class, I would test it separately.

In upcoming posts I will explain my implementation of the DynamicContext, Anonymous, and custom TestAssertion classes.

-=CE=-

This entry was posted in Agile, Test-Driven Development, Testing and tagged , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

Post a Comment

Your email is never published nor shared. Required fields are marked *

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*
*