2011/04/04

Unit tests initialization in Visual Studio 2010

NHDatabaseScopes problem
I am going to dig into a nasty detail of SqliteInMemorySharedScope class in this post. The FNH configuration is built by the constructor of this class. NH configuration needs to know which assembly to load the mapping metadata from. If the knowledge is included right in the constructor then the SqliteInMemorySharedScope (like in previous post) is coupled with tested domain model and cannot be reused in other project. It would be neat to inject the metadata or just the configuration into it. The configuration and session factory is shared between all unit tests and there is usually no particular execution order defined for tests. The question is: how to inject all information needed by SqliteInMemorySharedScope?

Unit test initialization
VS2010 offers a way how run a code before any test is executed. Just decorate a static method in test class with AssemblyInitialize attribute:
[TestClass]
public class TestEnvironmentInitialization
{
   [AssemblyInitialize]
   public static void Initialize(TestContext context)
   {
      // any initialization code

Some code can be executed after all tests were finished as well – attribute AssemblyCleanup.
The execution order is:
1)    Static method marked by AssemblyInitialize attribute.
2)    Default constructor of a test class.
3)    Method marked by TestInitialize attribute.
4)    Method marked by TestMethod attribute.
5)    Method marked by TestCleanup attribute.
6)    Static method marked by AssemblyCleanup attribute.

SqliteInMemorySharedScope decoupling from domain model
Back to the SqliteInMemorySharedScope class. A delegate that builds NH configuration is injected instead of configuration itself. The advantage, but questionable, is lazy initialization. Configuration is built only when it is really needed.
SqliteInMemorySharedScope initialization:
[TestClass]
public class TestEnvironmentInitialization
{
    private static NHibernate.Cfg.Configuration BuildSqliteConfiguration(string connectionString)
    {
    var config = Fluently.Configure()
        .Database(SQLiteConfiguration.Standard.ConnectionString(connectionString))
        .Mappings(m => {
            m.FluentMappings.AddFromAssembly(typeof(Order).Assembly);
        })
        .BuildConfiguration();

    return config;
}

[AssemblyInitialize]
public static void Initialize(TestContext context)
{
    BuildConfiguration = BuildSqliteConfiguration;

And simple modification of SqliteInMemorySharedScope:
public class SqliteInMemorySharedScope
{
    public static Func<string, NHibernate.Cfg.Configuration> BuildConfiguration;

   public SqliteInMemorySharedScope()
   {
      if (configuration == null) {
         configuration = BuildConfiguration(connectionString);
      }
SqliteInMemorySharedScope is decoupled from the domain model now and can be reused in multiple projects.

Source code can be downloaded here.

No comments:

Post a Comment