0

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 ?

Tom Carter
  • 2,938
  • 1
  • 27
  • 42
  • 1
    Is it possible that there is no open transaction during your tests? Do you use the Integration test helper class from Spring? Have you tried enabling logging for Spring and NHibernate to see whats happening (transaction wise) behind the scenes? Maybe you should also ask in the http://forum.springframework.net/ if you don't receive a sufficient answer. I haven't had the opportunity to work with OSIV yet :-( – tobsen Dec 05 '09 at 17:40
  • Having no open transaction causes the problem. See the accepted answer - thanks for your help +1 – Tom Carter Jan 15 '10 at 16:24

2 Answers2

1

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
  • 6,586
  • 25
  • 29
1

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
  • 2,938
  • 1
  • 27
  • 42