// ThomasWeller

C#/.NET software development, software integrity, life as a freelancer, and all the rest


News

Stack Overflow profile for Thomas Weller
Thomas Weller on bitbucket.org


Gallio Banner

Mercurial

Typemock Isolator

Can’t code without   The best C# coding assistance and
    refactoring plugin for Visual Studio

My Stats

  • Posts - 43
  • Comments - 135
  • Trackbacks - 0

Tag Cloud


Recent Comments


Recent Posts


Archives


Post Categories


Free e-Books


Toolbox: Development


Toolbox: Documentation


Toolbox: Productivity


Toolbox: Static analysis


Toolbox: Testing


Toolbox: Textual analysis



Let's face it: Setting up NHibernate is not one of the easiest tasks. You need a good knowledge of the system, and you need to write some configuration xml to your config files (well, normally). This is not such a big deal for the main project, since you only have to do it once in a project's lifetime. But you also have to care about setting it up for each and every test project that uses NHibernate, and there might be a lot of them if you're consequently unit testing just about everything.

So, wouldn't it be nice if declaring a test fixture with NH-support would be as easy as this:

[TestFixture]

public class SampleFixture : NHibernateFixtureBase

{

    public SampleFixture()

        : base("Some.Mapping.Assembly", "SOMESERVER", "SOMEDB", "test", "test")

    {

    }

 

    [Test]

    public void TestMethod()

    {

        using (ISession session = SessionFactory.OpenSession())

        {

            // test code goes here...

        }

    }

}

As you can see, you just have to specify the name of the assembly with the relevant NH mappings in the constructor, together with the database credentials, and that's it. The base class then creates the appropriate SessionFactory instance for you on the fly, without any additional configuration. Here it is:

using System.Reflection;

using NHibernate;

using NHibernate.ByteCode.Castle;

using NHibernate.Cfg;

using NHibernate.Dialect;

using NHibernate.Driver;

using Environment=NHibernate.Cfg.Environment;

 

namespace DbDevelopment.Persistence.Test.Common

{

    /// <summary>

    /// Base class for a test fixture with NHibernate + MS  SQL Server support.

    /// </summary>

    /// <remarks>

    /// Use the c'tor to specify the mapping-assembly and the database credentials.

    /// </remarks>

    public abstract class NHibernateFixtureBase

    {

        #region Fields

 

        protected ISessionFactory SessionFactory;

 

        #endregion // Fields

 

        #region Construction

 

        protected NHibernateFixtureBase(string assemblyWithMappings,

                                        string serverName, string databaseName,

                                        string username, string password)

        {

            CreateSessionFactory(

                assemblyWithMappings,

                BuildConnectionString(serverName, databaseName, username, password));

        }

 

        #endregion // Construction

 

        #region Implementation

 

        private void CreateSessionFactory(string assemblyName, string connectionString)

        {

            Assembly assemblyWithMappings = Assembly.Load(assemblyName);

 

            this.SessionFactory = new Configuration()

                .SetProperty(Environment.ReleaseConnections, "on_close")

                .SetProperty(Environment.Dialect, typeof(MsSql2005Dialect).AssemblyQualifiedName)

                .SetProperty(Environment.ShowSql, "true")

                .SetProperty(Environment.ConnectionDriver, typeof(SqlClientDriver).AssemblyQualifiedName)

                .SetProperty(Environment.ConnectionString, connectionString)

                .SetProperty(Environment.ProxyFactoryFactoryClass,typeof(ProxyFactoryFactory).AssemblyQualifiedName)

                .AddAssembly(assemblyWithMappings)

                .BuildSessionFactory();

        }

 

        private static string BuildConnectionString(string serverName, string databaseName,

                                                    string username, string password)

        {

            return string.Format(

                "Data Source={0};Initial Catalog={1};User ID={2};Password={3}",

                serverName, databaseName, username, password);

        }

 

        #endregion // Implementation

 

    } // class NHibernateFixtureBase

 

} // namespace DbDevelopment.Persistence.Test.Common

This example uses a MS SQL Server database (2005 or higher), but it could be easily modified to target a different DBMS by adjusting the BuildConnectionString() method along with the relevant configuration settings in CreateSessionFactory() accordingly.

Happy testing...

 

kickit
shoutit
delicious facebook digg reddit linkedin stumbleupon technorati mrwong yahoo google-48x48 twitter email favorites

Comments

Gravatar # re: Unit testing with built-in NHibernate support
Posted by Shaun on 9/11/2009 1:23 PM
Unit tests usually don't hit remote database servers. We do our NHibernate based unit testing using an in memory database with SQLite. It works out well and it keeps our tests isolated.
Gravatar # re: Unit testing with built-in NHibernate support
Posted by Thomas Weller on 9/11/2009 2:09 PM
Shaun,

sorry, but I have a totally different view on this in two respects:

1.
I consider the usage of SQLite for unit tests of this kind in general not a good idea. Because SQLite does not have all the features of a 'real' DBMS (e.g. no foreign key constraints), you create a testing environment that does not match your targeted production environment (by design!), and therefore such tests are useless in the strict sense. You can also read about this here (see the comments): http://devlicio.us/blogs/krzysztof_kozmic/archive/2009/08/17/adjusting-nhibernate-mapping-for-tests.aspx

2.
'Remote' in this context does of course not mean that you have one centralized database against that everyone is doing tests simultaneously. This of course would be a really bad idea. Normally I set these tests up so that the actual db credentials are read from some sort of local configuration and point to a local instance of the db for the actual testing on a developer's machine.

Your solution might work, but it does not safely protect you from faults in any situations. And even worse: if such a test produces an error, you cannot be sure if there's really something broken in your code or if it's just a test artifact.

- Thomas
Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: