背景
我的团队致力于确保直接结账,我们的代码编译和单元测试成功运行。为了实现这一点并测试我们的一些NHibernate映射,我们在我们的存储库中添加了一个SQLite DB,它是我们的生产SQL Server 2005数据库的镜像。我们使用的是最新版本:MbUnit3(Gallio的一部分),System.Data.SQLite和NHibernate。
问题:
我发现以下单元测试不能与SQLite一起使用,尽管对SQL Server 2005没有遇到麻烦。
[Test]
[Rollback]
public void CompleteCanPersistNode()
{
// returns a Configuration for either SQLite or SQL Server 2005 depending on how the project is configured.
Configuration config = GetDbConfig();
ISessionFactory sessionFactory = config.BuildSessionFactory();
ISession session = sessionFactory.OpenSession();
Node node = new Node();
node.Name = "Test Node";
node.PhysicalNodeType = session.Get<NodeType>(1);
// SQLite fails with the exception below after the next line called.
node.NodeLocation = session.Get<NodeLocation>(2);
session.Save(node);
session.Flush();
Assert.AreNotEqual(-1, node.NodeID);
Assert.IsNotNull(session.Get<Node>(node.NodeID));
}
我得到的异常(仅在使用SQLite时)如下:
NHibernate.ADOException: cannot open connection ---> System.Data.SQLite.SQLiteException: The database file is locked database is locked at System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt) at System.Data.SQLite.SQLiteDataReader.NextResult() at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave) at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior) at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery() at System.Data.SQLite.SQLiteTransaction..ctor(SQLiteConnection connection, Boolean deferredLock) at System.Data.SQLite.SQLiteConnection.BeginDbTransaction(IsolationLevel isolationLevel) at System.Data.SQLite.SQLiteConnection.BeginTransaction() at System.Data.SQLite.SQLiteEnlistment..ctor(SQLiteConnection cnn, Transaction scope) at System.Data.SQLite.SQLiteConnection.EnlistTransaction(Transaction transaction) at System.Data.SQLite.SQLiteConnection.Open() at NHibernate.Connection.DriverConnectionProvider.GetConnection() at NHibernate.Impl.SessionFactoryImpl.OpenConnection() --- End of inner exception stack trace --- at NHibernate.Impl.SessionFactoryImpl.OpenConnection() at NHibernate.AdoNet.ConnectionManager.GetConnection() at NHibernate.AdoNet.AbstractBatcher.Prepare(IDbCommand cmd) at NHibernate.AdoNet.AbstractBatcher.ExecuteReader(IDbCommand cmd) at NHibernate.Loader.Loader.GetResultSet(IDbCommand st, Boolean autoDiscoverTypes, Boolean callable, RowSelection selection, ISessionImplementor session) at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) at NHibernate.Loader.Loader.LoadEntity(ISessionImplementor session, Object id, IType identifierType, Object optionalObject, String optionalEntityName, Object optionalIdentifier, IEntityPersister persister) at NHibernate.Loader.Entity.AbstractEntityLoader.Load(ISessionImplementor session, Object id, Object optionalObject, Object optionalId) at NHibernate.Loader.Entity.AbstractEntityLoader.Load(Object id, Object optionalObject, ISessionImplementor session) at NHibernate.Persister.Entity.AbstractEntityPersister.Load(Object id, Object optionalObject, LockMode lockMode, ISessionImplementor session) at NHibernate.Event.Default.DefaultLoadEventListener.LoadFromDatasource(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options) at NHibernate.Event.Default.DefaultLoadEventListener.DoLoad(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options) at NHibernate.Event.Default.DefaultLoadEventListener.Load(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options) at NHibernate.Event.Default.DefaultLoadEventListener.ProxyOrLoad(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options) at NHibernate.Event.Default.DefaultLoadEventListener.OnLoad(LoadEvent event, LoadType loadType) at NHibernate.Impl.SessionImpl.FireLoad(LoadEvent event, LoadType loadType) at NHibernate.Impl.SessionImpl.Get(String entityName, Object id) at NHibernate.Impl.SessionImpl.Get(Type entityClass, Object id) at NHibernate.Impl.SessionImpl.Get[T](Object id) D:\dev\598\Code\test\unit\DataAccess.Test\NHibernatePersistenceTests.cs
当使用SQLite并且未指定[Rollback]属性时,测试也会成功完成。
问题:
这是一个问题,System.Data.SQLite的TransactionScope实现是MbUnit3用于[Rollback]还是限制了SQLite引擎?
有没有办法编写这个单元测试,反对SQLite,它会回滚,以避免每次运行测试时都影响数据库?
答案 0 :(得分:2)
这不是你问题的真正答案,但可能是解决问题的解决方案。
我使用sql lite的内存实现来进行集成测试。我在每次测试之前构建模式并填充数据库。模式创建和初始数据填充发生得非常快(每次测试少于0.01秒)因为它是内存数据库。
为什么使用物理数据库?
编辑:对上述问题的回答回复:
1。)因为我直接从SQL Server 2005迁移了我的架构和数据,我希望它在源代码控制中持久存在。
2。)内存中的SQLite引擎有什么不同之处,以至于它可以解决这个难题吗?
答案 1 :(得分:1)
检查您的SQLite NHibernate配置中是否遗漏了connection.release_mode=on_close
。 (reference docs)
BTW:始终处置您的ISession
和ISessionFactory
。
答案 2 :(得分:0)
Ditch [Rollback]并使用NDbUnit。我自己就是用这个确切的场景而且它一直很好用。