Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Testing NHibernate Mappings

DZone's Guide to

Testing NHibernate Mappings

· Database Zone
Free Resource

Learn how to move from MongoDB to Couchbase Server for consistent high performance in distributed environments at any scale.

I’m currently in the process of moving Suteki Shop from Linq-to-SQL to NHibernate. It turns out to be a bigger job than I anticipated, and I’ll be writing a post about my experiences soon. I’m using FNH (Fluent NHibernate) to build my mapping files rather than use the tedious built-in XML mapping. One of the big jobs I have is to write unit tests for all the mapping files. For each entity, I want to have a test that creates an instance of it, saves it to the database, and retrieves it. As you can imagine, it would be a tedious task to write all these. With that in mind I’ve created a simple NUnit test that can be reused for any mapped entity:

using System;
using System.Reflection;
using NUnit.Framework;
using Suteki.Common.Extensions;
using Suteki.Shop.Tests.Models.Builders;

namespace Suteki.Shop.Tests.Maps
{
/// <summary>
/// Runs a simple test for each entity listed. That it can be saved to the database and retrieved.
/// </summary>
[TestFixture]
public class SimpleMapTests : MapTestBase
{
[TestCase(typeof (PostZone))]
[TestCase(typeof (Postage))]
[TestCase(typeof (Country))]
public void SimpleMapTest(Type entityType)
{
var runSimpleMapTest = GetType().GetMethod("RunSimpleMapTest");
var runSimpleMapTestForType = runSimpleMapTest.MakeGenericMethod(entityType);
runSimpleMapTestForType.Invoke(this, new object[0]);
}

public void RunSimpleMapTest<TEntity>() where TEntity : class, new()
{
var id = 0;

InSession(session =>
{
var entity = GetDefaultsFor<TEntity>();

session.Save(entity);
id = (int) entity.GetPrimaryKey().Value;
});

InSession(session => session.Get<TEntity>(id));
}

static TEntity GetDefaultsFor<TEntity>()
{
var entityName = typeof (TEntity).Name;
var defaults = typeof(Default).GetMethod(entityName, BindingFlags.Static | BindingFlags.Public);
if (defaults == null)
{
Assert.Fail(string.Format("No static method Default.{0} found", entityName));
}
if (defaults.ReturnType != typeof (TEntity))
{
Assert.Fail(string.Format("Method Default.{0} does not have a return type of {0}", entityName));
}

return (TEntity) defaults.Invoke(null, new object[0]);
}
}
}

The core idea here is to use the NUnit TestCase attribute to run a test for each entity that I want to map. I have a generic test method ‘RunSimpleMapTest<TEntity>’ that gets called for each entity by ‘SimpleMapTest’. There’s a little bit of reflection voodoo to create and run a correctly typed ‘RunSimpleMapTest’, but the principle is simple.

RunSimpleMapTest gets a default instance of the entity class, saves it, grabs the generated id, and then retrieves the entity again using the id. This is enough to check that the basic map works and that I don’t have any non-virtual members in my entity. The ‘InSession’ method is just to save some typing, it looks like this:

protected void InSession(Action<ISession> action)
{
using (var session = InMemoryDatabaseManager.OpenSession())
using(var transaction = session.BeginTransaction())
{
action(session);
transaction.Commit();
}
}

The GetPrimaryKey method is an extension method that finds the primary key of any entity based on a simple convention; my primary keys are always called ‘Id’ or ‘<entity name>Id’.

I’m using an in-memory SQLite database for the tests that’s managed by the MapTestBase base class. This is such a common solution that I’ll just leave you to Google it rather than showing my implementation here.

The last thing to note, is where the actual entity instance comes from. The GetDefaultsFor<TEntity> method looks for a method with the same name as the entity in a class called ‘Default’. The default method for PostZone looks like this:

public static class Default
{
public static PostZone PostZone()
{
return new PostZone
{
Name = "UK",
Multiplier = 1.0M,
AskIfMaxWeight = false,
Position = 1,
IsActive = true,
FlatRate = 10M
};
}

.... lots of other similar methods
}

Now for each entity, I simply create the ClassMap, create a method to make a default entity in the Default class and add a new TestCase attribute to my test.

 

Topics:

Published at DZone with permission of Mike Hadlow, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}