Unit testing NHibernate mappings

When one starts to learn NHibernate, a question that is very popular is which approach you should use to map your domain classes to the database.

After doing some research, the answer for me is: it doesn’t mater, specially if you have good Unit Tests in place to validate your mappings. At the end, the same mapping issue that you will face using HBM files, you will face using FHN or Mapping By Code.

Because of that, I did some experiments on what would be a good approach to unit test NHibernate Mappings. I ended up using NUnit and SQLite. I’m quite happy with the result and I feel confident about writing unit tests using it.

Project Setup

All the source code used in this post is also available here. The NuGet packages used were the following.

Because of NUnit3TestAdapter, I don’t need any extension to run my tests on Visual Studio.

The In-Memory Helper Class

This is the NHibernate helper class that will be used to create a new in-memory database. It is designed to create a new in-memory instance of SQLite database for each object. Doing so, you can completely isolate your unit tests with it’s own contained database.

using NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Tool.hbm2ddl;
using System.Data.SQLite;

namespace Persistence
{
  public class InMemorySessionHelper
  {
    private const string CONNECTION_STRING =
      "Data Source=:memory:;Version=3;New=True;";

    private Configuration _config;
    private ISessionFactory _sessionFactory;
    private SQLiteConnection _connection;

    public InMemorySessionHelper()
    {
      _config = new Configuration()
        .DataBaseIntegration(db =>
        {
          db.Dialect<SQLiteDialect>();
          db.Driver<SQLite20Driver>();
          db.ConnectionString = CONNECTION_STRING;
        })
        .SetNamingStrategy(ImprovedNamingStrategy.Instance)
        .AddAssembly("Persistence");

      _sessionFactory = _config.BuildSessionFactory();
    }

    public ISession OpenSession()
    {
      return _sessionFactory.OpenSession(GetConnection());
    }

    private SQLiteConnection GetConnection()
    {
      if (_connection == null)
      {
        _connection = new SQLiteConnection(CONNECTION_STRING);
        _connection.Open();

        SchemaExport se = new SchemaExport(_config);
        se.Execute(true, true, false, _connection, null);
      }

      return _connection;
    }
  }
}

Again, you can check the full source code for the project here.

Base Test Fixture Class

This is the BaseInMemoryFixture, it is designed to create a new instance of the database for each Test Fixture. We could create a new instance of InMemorySessionHelper for each unit test but, for what I did so far, running them per test class was enough.

using NHibernate;
using NUnit.Framework;
using Persistence;

namespace Tests.Mappings
{
  public class BaseInMemoryFixture
  {
    private InMemorySessionHelper _sessionHelper;

    [OneTimeSetUp]
    public void Setup()
    {
      _sessionHelper = new InMemorySessionHelper();
    }

    protected ISession OpenSession()
    {
      return _sessionHelper.OpenSession();
    }
  }
}

The OpenSession method will be used to create new sessions inside each unit test.

A Sample Mapping Unit Test

This is a sample test to demonstrate how we can extend the BaseInMemoryFixture class to execute a unit test that validates the data mapping for the Template Fields property.

using Domain.Entities;
using NUnit.Framework;
using System.Linq;

namespace Tests.Mappings
{
  [TestFixture]
  public class TemplateMappingFixture : BaseInMemoryFixture
  {
    [Test]
    public void TemplateFieldsProperty()
    {
      object entityId = null;

      using (var session = OpenSession())
      {
        using (var transaction = session.BeginTransaction())
        {
          var template = new Template();
          template.AddField(new Field("FieldOne"));
          template.AddField(new Field("FieldTwo"));

          entityId = session.Save(template);

          transaction.Commit();
        }
      }

      using (var session = OpenSession())
      {
        using (var transaction = session.BeginTransaction())
        {
          var entity = session.Get<Template>(entityId);

          Assert.NotNull(entity);
          Assert.NotNull(entity.Fields);
          Assert.AreEqual(2, entity.Fields.Count);
          Assert.Contains("FieldOne",
           entity.Fields.Select(x => x.Name).ToList());
          Assert.Contains("FieldTwo",
           entity.Fields.Select(x => x.Name).ToList());
        }
      }
    }
  }
}

The point here is that you don’t need to hit a real database, or even you development database, to validate that your ORM is working as expected.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s