We are reusing DAOs within Web code to integration code and the session management behavior is different in each one. I am also using the Spring.Net however this should work anywhere that you are injecting ISessionFactory and you are using SessionFactory.GetCurrentSession() to get your session.
Basically we're using the same code as in his example except we are using Rhino Mock to actually mock the SessionFactory. In addition we are exposing the SessionFactory so that you can inject it into your DAOs. We are still exposing the Session for use in your test fixture.
public class InMemoryDatabaseTest : IDisposable
{
private static Configuration Configuration;
private MockRepository _mocks;
private static ISessionFactory _realSessionFactory;
private ISession _session;
private ISessionFactory _sessionFactory;
protected ISession Session
{
get { return _sessionFactory.GetCurrentSession(); } // simulates how DAOs are getting their Sessions
}
///
/// Gets the SessionFactory
///
public ISessionFactory SessionFactory
{
get { return _sessionFactory; }
}
public InMemoryDatabaseTest(Assembly assemblyContainingMapping)
{
_mocks = new MockRepository();
if (Configuration == null)
{
Configuration = new Configuration()
.SetProperty(NHibernate.Cfg.Environment. ReleaseConnections, "on_close")
.SetProperty(NHibernate.Cfg.Environment.Dialect, typeof(SQLiteDialect). AssemblyQualifiedName)
.SetProperty(NHibernate.Cfg.Environment.ConnectionDriver, typeof(SQLite20Driver). AssemblyQualifiedName)
.SetProperty(NHibernate.Cfg.Environment.ConnectionString, "data source=:memory:")
.SetProperty(NHibernate.Cfg.Environment. ProxyFactoryFactoryClass, typeof( DefaultProxyFactoryFactory). AssemblyQualifiedName)
.AddAssembly(assemblyContainingMapping);
_realSessionFactory = Configuration.BuildSessionFactory();
}
// Here we are mocking the Session Factory because we are using Session Scopes.
// However we want to return the same session every time
_sessionFactory = _mocks.CreateMock<ISessionFactory>();
_session = _realSessionFactory.OpenSession();
Expect.Call(_sessionFactory.GetCurrentSession()). IgnoreArguments().Return(_ session).Repeat.Any();
_mocks.ReplayAll();
new SchemaExport(Configuration).Execute(true, true, false, true, _session.Connection, Console.Out);
}
public void Dispose()
{
Session.Dispose();
}
}
The Mock is the glue that makes this work so that you can adhere to the restrictions of your DAO implementation. Then you can execute the test much like Ayende does in his own, regardless of how your perform transaction management in your actual application.
[TestFixture]
public class FelineDao_Tests : InMemoryDatabaseTest
{
public FelineDao_Tests() : base(typeof(Feline).Assembly) { }
[TestFixtureSetUp]
public void Initialize()
{
// Insert Test data
using (ITransaction tx = Session.BeginTransaction())
{
Session.Save(GetSnowLeopard());
Session.Save(GetDomesticCat());
tx.Commit();
}
Session.Clear();
}
[Test]
public void FindAll_Retrieval()
{
using (ITransaction tx = Session.BeginTransaction())
{
Daodao = new Dao ();
dao.SessionFactory = SessionFactory;
IListlist = dao.FindAll();
Assert.AreEqual(2, list.Count);
tx.Commit();
}
}
[Test]
public void FindById_Retrieval_InValid_Id()
{
using (ITransaction tx = Session.BeginTransaction())
{
Daodao = new Dao ();
dao.SessionFactory = SessionFactory;
Feline o = dao.FindById(3);
Assert.IsNull(o);
tx.Commit();
}
}
[Test]
public void FindById_Retrieval_Valid_Id()
{
using (ITransaction tx = Session.BeginTransaction())
{
Daodao = new Dao ();
dao.SessionFactory = SessionFactory;
Feline o = dao.FindById(1);
Assert.IsNotNull(o);
tx.Commit();
}
}
private Feline GetSnowLeopard()
{
Feline feline = new Feline();
feline.Name = "Snow Leopard";
feline.Length = 74;
return feline;
}
private Feline GetDomesticCat()
{
Feline feline = new Feline();
feline.Name = "Domestic Cat";
feline.Length = 24;
return feline;
}
}
Props to Ayende for the original implementation of this and for his work on Rhino Mocks.
2 comments:
What is the session context you are using, and where do you set and bind it to the session factory?
If the context is ThreadStaticSessionContext wouldn't GetCurrentSession() always be returning the same session anyway?
Cheers,
Berryl
it would return the same session, basically I'm faking contextual sessions by mocking the SessionFactory. I have a new version I'll post that actually binds it to a thread which works similarly.
Post a Comment