我使用NHibernate作为我的dataacess,有一段时间我并没有使用SQLite进行本地集成测试.我一直在使用文件,但我想我会把:memory:选项.当我启动任何集成测试时,似乎创建了数据库(NHibernate吐出表创建sql)但是与数据库交互会导致错误.
有没有人让NHibernate与内存数据库一起工作?它甚至可能吗?我正在使用的连接字符串是这样的:
Data Source=:memory:;Version=3;New=True
Sean Carpent.. 41
只要与它的连接保持打开状态,SQLite内存数据库就只存在.要在NHibernate的单元测试中使用它:
1.在测试开始时打开一个ISession(可能在[SetUp]方法中).
2.在SchemaExport调用中使用该会话的连接.
3.在测试中使用相同的会话.
4.在测试结束时关闭会话(可能在[TearDown]方法中).
只要与它的连接保持打开状态,SQLite内存数据库就只存在.要在NHibernate的单元测试中使用它:
1.在测试开始时打开一个ISession(可能在[SetUp]方法中).
2.在SchemaExport调用中使用该会话的连接.
3.在测试中使用相同的会话.
4.在测试结束时关闭会话(可能在[TearDown]方法中).
我能够使用SQLite内存数据库,并且避免使用SQLite 对"共享缓存"的支持来重建每个测试的模式,这允许在连接之间共享内存数据库.
我在AssemblyInitialize中做了以下(我正在使用MSTest):
配置NHibernate(Fluently)以使用带有以下连接字符串的SQLite:
FullUri=file:memorydb.db?mode=memory&cache=shared
使用该配置创建hbm2ddl.SchemaExport对象,并在单独的连接上执行它(但再次使用相同的连接字符串).
保持该连接打开,并由静态字段引用,直到AssemblyCleanup,此时它将被关闭并丢弃.这是因为SQLite至少需要在内存数据库中保存一个活动连接才能知道它仍然需要并避免整理.
在每个测试运行之前,会创建一个新会话,并且测试将在最后回滚的事务中运行.
以下是测试程序集级代码的示例:
[TestClass] public static class SampleAssemblySetup { private const string ConnectionString = "FullUri=file:memorydb.db?mode=memory&cache=shared"; private static SQLiteConnection _connection; [AssemblyInitialize] public static void AssemblyInit(TestContext context) { var configuration = Fluently.Configure() .Database(SQLiteConfiguration.Standard.ConnectionString(ConnectionString)) .Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.Load("MyMappingsAssembly"))) .ExposeConfiguration(x => x.SetProperty("current_session_context_class", "call")) .BuildConfiguration(); // Create the schema in the database // Because it's an in-memory database, we hold this connection open until all the tests are finished var schemaExport = new SchemaExport(configuration); _connection = new SQLiteConnection(ConnectionString); _connection.Open(); schemaExport.Execute(false, true, false, _connection, null); } [AssemblyCleanup] public static void AssemblyTearDown() { if (_connection != null) { _connection.Dispose(); _connection = null; } } }
每个单元测试类/ fixture的基类:
public class TestBase { [TestInitialize] public virtual void Initialize() { NHibernateBootstrapper.InitializeSession(); var transaction = SessionFactory.Current.GetCurrentSession().BeginTransaction(); } [TestCleanup] public virtual void Cleanup() { var currentSession = SessionFactory.Current.GetCurrentSession(); if (currentSession.Transaction != null) { currentSession.Transaction.Rollback(); currentSession.Close(); } NHibernateBootstrapper.CleanupSession(); } }
我承认,资源管理可以改进,但毕竟这些都是单元测试(欢迎建议改进!).
我们在内存中使用SQLite进行所有数据库测试.我们使用单个ADO连接进行测试,这些测试可以重复用于同一测试打开的所有NH会话.
在每次测试之前:创建连接
在此连接上创建架构
运行测试.所有会话都使用相同的连接
测试后:关闭连接
这允许运行包含多个会话的测试.SessionFactory也为所有测试创建一次,因为读取映射文件需要相当长的时间.
编辑
从System.Data.Sqlite 1.0.82(或Sqlite 3.7.13)开始,有一个共享缓存,它允许多个连接共享相同的数据,也适用于内存数据库.这允许在一个连接中创建内存数据库,并在另一个连接中使用它.(我还没试过,但从理论上讲,这应该有效):
将连接字符串更改为 file::memory:?cache=shared
打开连接并创建架构
保持此连接打开,直到测试结束
让NH在测试期间创建其他连接(正常行为).
我有类似的问题,即使在打开如上所述的ISession之后,并且在我的连接字符串中添加"Pooling = True; Max Pool Size = 1".它有所帮助,但我仍然遇到一些情况,在测试期间连接会关闭(通常在提交事务之后).
最终对我有用的是在我的SessionFactory配置中将属性"connection.release_mode"设置为"on_close".
我在app.config文件中的配置现在看起来像这样:
testSqlLiteDB NHibernate.Driver.SQLite20Driver NHibernate.Connection.DriverConnectionProvider on_close NHibernate.Dialect.SQLiteDialect NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle true=1;false=0
希望能帮助到你!