views:

270

answers:

2

We have a web application based on NSpring 1.2 and NHibernate 2 and use HibernateTemplate. The web application is configured to use OpenSessionInViewModule.

In our integration tests however the hibernate session is marked as InitDeferredClose and for the most part this works fine for our tests. There are some service functions that work fine in the context of the web application but fail when called from a test harness.

For example : I have one function that creates and updates a number of objects within a transaction. The function is marked with the Transaction attribute but the test fails with the message :

Illegal attempt to associate a collection with two open sessions

When called from the web application the transaction completes successfully

How should I be configuring spring and hibernate so that my Integration Tests replicate properly the functionnality of the Web application ?

+1  A: 

You should create a SessionScope instance in the SetUp part of test and then close (dispose) it at the end (TearDown). This should mimic OSIV model quite well. Here's a simplified sample:

using System;
using NHibernate;
using NUnit.Framework;
using Spring.Data.NHibernate.Support;

[TestFixture]
public class OsivKindOfTest
{
    private SessionScope scope;
    // get LocalSessionFactoryObject from somewhere
    // see Spring.Testing.NUnit and auto-injection
    private ISessionFactory sessionFactory;

    [SetUp]
    public void OnSetUp()
    {
        scope = new SessionScope(sessionFactory, null, true, FlushMode.Never, true);
    }

    public void TestSomething()
    {
        // just a dummy demo
        Console.WriteLine(sessionFactory.GetCurrentSession().Statistics.EntityCount);
    }

    [TearDown]
    public void TearDown()
    {
        if (scope != null)
        {
            scope.Dispose();
        }
    }
}

This sample expects that Spring's LocalSessionFactoryObject has ExposeTransactionAwareSessionFactory set to true

Marko Lahma
The Session Scope didn't seem to help - thanks though ...
Tom Carter
A: 

I have rewritten my integration test fixtures to inherit from the AbstractTransactionalDbProviderSpringContextTests class provided by the Spring testing framework.

This indeed runs each test in its own transaction with a (by default) rollback at the end of the test. Apart from solving the problem of two open sessions, my tests run a lot quicker (no need to clear the database each time).

An important point to keep in mind when using the spring testing framework is that it is necessary to ensure the spring application context of the application code and that of the test framework are the one and the same otherwise the outer transaction and the inner transaction would be created by two different Hibernate Session Factories

Tom Carter