代码之家  ›  专栏  ›  技术社区  ›  antik

使用MbUnit3的[Rollback]对NHibernate与SQLite的交互进行单元测试

  •  2
  • antik  · 技术社区  · 17 年前

    背景:

    我的团队致力于确保直接从签出开始,我们的代码编译和单元测试就能成功运行。为了促进这一点并测试一些NHibernate映射,我们在存储库中添加了一个SQLite DB,它是生产SQL Server 2005数据库的镜像。我们正在使用最新版本的:MbUnit3(Gallio的一部分)、System.Data.SQLite和NHibernate。

    问题:

    我发现下面的单元测试不适用于SQLite,尽管对SQLServer2005执行时没有遇到问题。

        [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));
        }
    

    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
    

    问题:

    这是因为System.Data.SQLite实现了MbUnit3用于[Rollback]的TransactionScope,还是因为SQLite引擎的限制?

    3 回复  |  直到 17 年前
        1
  •  2
  •   Paco    17 年前

    我在集成测试中使用SQLLite的内存实现。在每次测试之前,我建立模式并填充数据库。模式创建和初始数据填充速度非常快(每个测试少于0.01秒),因为它是内存中的数据库。

    为什么要使用物理数据库?

    编辑:对上述问题答案的回复:

    1.)因为我直接从SQLServer2005迁移了架构和数据,并且希望它在源代码管理中持久化。

    • 我建议在中存储一个带有数据库模式的文件,并在源代码管理中存储一个创建示例数据的文件或脚本。您可以使用sql server studion management express生成该文件,也可以从NHibernate映射生成该文件,或者可以使用sql compare之类的工具,并且在需要时可能会找到其他解决方案。纯文本文件比完整的二进制数据库文件更容易存储在版本控制系统中。

        2
  •  1
  •   Mauricio Scheffer    17 年前

    检查你是否失踪 connection.release_mode=on_close reference docs )

    顺便说一句:总是处理你的垃圾 ISession ISessionFactory .

        3
  •  0
  •   remotefacade    17 年前

    沟渠[回滚]并使用 NDbUnit . 我自己也在这个场景中使用它,它一直工作得很好。

    推荐文章