I've got a class, which should work as a Singleton per Thread. It has single static method returing thread-shared object of Isession type (this is NHibernate object).
I've got different tests on it, one of them is to check that actually different instances are returned for different threads (there is also separated test, which checks that instance is the same within one thread; this test is not here).
When test starts, it Mock several type, using DynamicReturnValue. This is crusual, as I need that each mocked invokation of BuildSessionFactory() and OpenSession() actually creates new mocked instance of needed type.
When I start the code and run the test, it shows exception on line:
session = sessionFactory.OpenSession();
with the message:
Tests.HibernateUtilsTest.CurrentSessionNotNull : TypeMock.VerifyException :
TypeMock Verification: Unexpected Call to NHibernate.ISessionFactory.OpenSession(?)
TearDown : System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
----> TypeMock.VerifyException :
TypeMock Verification: Expected a new instance of MockISessionFactory (try using MockAll)
Method MockISessionFactory.OpenSession() has 1 more expected calls
And Nunit falls :(
Tested class:
using NHibernate;
using NHibernate.Cfg;
public class HibernateUtils
{
private const string CurrentSessionContextKey = "ED88E670-C22D-408a-B2DE-954DC79E1228";
private static ISessionFactory sessionFactory = null;
static HibernateUtils()
{
Configuration cfg = new Configuration();
sessionFactory = cfg.BuildSessionFactory();
}
public static ISession CurrentSession
{
get
{
ISession session = ExecutionContext.Current.Items[CurrentSessionContextKey] as ISession;
if (session == null)
{
session = sessionFactory.OpenSession();
ExecutionContext.Current.Items[CurrentSessionContextKey] = session;
}
return session;
}
}
}
Fixture:
[TestFixture]
public class HibernateUtilsTest : TestBase
{
private ISession session;
private Mock configMockType;
private MockObject sessionFactoryMockObject;
private MockObject sessionMockObject;
[SetUp]
protected override void TestStart()
{
this.MockHibernate();
}
protected virtual void MockHibernate()
{
configMockType = MockManager.Mock(typeof(Configuration));
configMockType.AlwaysReturn("BuildSessionFactory", new DynamicReturnValue(CreateSessionFactoryMockObject));
configMockType.Strict = true;
}
protected virtual object CreateSessionFactoryMockObject(object[] parameters, object context)
{
sessionFactoryMockObject = MockManager.MockObject(typeof(ISessionFactory));
sessionFactoryMockObject.ExpectAndReturn("OpenSession", new DynamicReturnValue(CreateSessionMockObject));
return sessionFactoryMockObject.Object;
}
protected virtual object CreateSessionMockObject(object[] parameters, object context)
{
sessionMockObject = MockManager.MockObject(typeof(ISession));
return sessionMockObject.Object;
}
[Test]
public void CurrentSessionDiffersInMutliThreads()
{
IList<ISession> sessions = this.GetSessionsFromDifferentThreads(2);
this.InitSession();
Assert.AreNotSame(this.session, sessions[0]);
Assert.AreNotSame(this.session, sessions[1]);
Assert.AreNotSame(sessions[0], sessions[1]);
}
private IList<ISession> GetSessionsFromDifferentThreads(int threadsCount)
{
IList<ISession> retList = new List<ISession>();
for (int i = 0; i < threadsCount; i++)
{
this.StartAnotherThreadMethodAndWait(new ThreadStart(this.InitSession));
retList.Add(this.session);
}
return retList;
}
protected virtual void StartAnotherThreadMethodAndWait(ThreadStart methodToStart)
{
Thread anotherThread = new Thread(methodToStart);
anotherThread.Start();
anotherThread.Join();
}
public void InitSession()
{
this.session = HibernateUtils.CurrentSession;
}
}