2

背景:

我的团队致力于确保直接从结帐,我们的代码编译和单元测试成功运行。为了促进这一点并测试我们的一些 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:无法打开连接--->
System.Data.SQLite.SQLiteException:
  数据库文件被锁定 数据库被锁定
    在 System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt)
    在 System.Data.SQLite.SQLiteDataReader.NextResult()
    在 System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd,CommandBehavior 行为)
    在 System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior 行为)
    在 System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
    在 System.Data.SQLite.SQLiteTransaction..ctor(SQLiteConnection 连接,布尔 deferredLock)
    在 System.Data.SQLite.SQLiteConnection.BeginDbTransaction(IsolationLevel 隔离级别)
    在 System.Data.SQLite.SQLiteConnection.BeginTransaction()
    在 System.Data.SQLite.SQLiteEnlistment..ctor(SQLiteConnection cnn,事务范围)
    在 System.Data.SQLite.SQLiteConnection.EnlistTransaction(事务事务)
    在 System.Data.SQLite.SQLiteConnection.Open()
    在 NHibernate.Connection.DriverConnectionProvider.GetConnection()
    在 NHibernate.Impl.SessionFactoryImpl.OpenConnection()
    --- 内部异常堆栈跟踪结束 ---
    在 NHibernate.Impl.SessionFactoryImpl.OpenConnection()
    在 NHibernate.AdoNet.ConnectionManager.GetConnection()
    在 NHibernate.AdoNet.AbstractBatcher.Prepare(IDbCommand cmd)
    在 NHibernate.AdoNet.AbstractBatcher.ExecuteReader(IDbCommand cmd)
    在 NHibernate.Loader.Loader.GetResultSet(IDbCommand st, Boolean autoDiscoverTypes, Boolean callable, RowSelection selection, ISessionImplementor session)
    在 NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
    在 NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor 会话,QueryParameters 查询参数,布尔 returnProxies)
    在 NHibernate.Loader.Loader.LoadEntity(ISessionImplementor 会话,对象 id,IType 标识符类型,对象 optionalObject,字符串 optionalEntityName,对象 optionalIdentifier,IEntityPersister 持久化)
    在 NHibernate.Loader.Entity.AbstractEntityLoader.Load(ISessionImplementor 会话,对象 id,对象 optionalObject,对象 optionalId)
    在 NHibernate.Loader.Entity.AbstractEntityLoader.Load(对象 id,对象 optionalObject,ISessionImplementor 会话)
    在 NHibernate.Persister.Entity.AbstractEntityPersister.Load(对象 id,对象 optionalObject,LockMode lockMode,ISessionImplementor 会话)
    在 NHibernate.Event.Default.DefaultLoadEventListener.LoadFromDatasource(LoadEvent 事件,IEntityPersister 持久化,EntityKey keyToLoad,LoadType 选项)
    在 NHibernate.Event.Default.DefaultLoadEventListener.DoLoad(LoadEvent 事件,IEntityPersister 持久化,EntityKey keyToLoad,LoadType 选项)
    在 NHibernate.Event.Default.DefaultLoadEventListener.Load(LoadEvent 事件,IEntityPersister 持久化,EntityKey keyToLoad,LoadType 选项)
    在 NHibernate.Event.Default.DefaultLoadEventListener.ProxyOrLoad(LoadEvent 事件,IEntityPersister 持久化,EntityKey keyToLoad,LoadType 选项)
    在 NHibernate.Event.Default.DefaultLoadEventListener.OnLoad(LoadEvent 事件,LoadType loadType)
    在 NHibernate.Impl.SessionImpl.FireLoad(LoadEvent 事件,LoadType loadType)
    在 NHibernate.Impl.SessionImpl.Get(字符串 entityName,对象 id)
    在 NHibernate.Impl.SessionImpl.Get(类型 entityClass,对象 id)
    在 NHibernate.Impl.SessionImpl.Get[T](对象 id)
D:\dev\598\Code\test\unit\DataAccess.Test\NHibernatePersistenceTests.cs

当使用 SQLite 并且未指定 [Rollback] 属性时,测试也成功完成。

问题:

这是 MbUnit3 用于 [Rollback] 的 System.Data.SQLite 的 TransactionScope 实现的问题还是 SQLite 引擎的限制?

有没有办法编写这个单元测试,针对 SQLite,回滚以避免每次运行测试时影响数据库?

4

3 回答 3

2

这不是您问题的真正答案,但可能是解决问题的解决方案。

我使用 sql lite 的内存实现进行集成测试。我在每次测试之前建立架构并填充数据库。模式创建和初始数据填充发生得非常快(每次测试不到 0.01 秒),因为它是一个内存数据库。

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

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

1.) 因为我直接从 SQL Server 2005 迁移了我的架构和数据,并且我希望它保留在源代码管理中。

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

2.) 内存中的 SQLite 引擎是否有所不同以解决这个困难?

  • 它可能会解决您的问题,因为您可以在每次测试之前重新创建数据库。在执行每个测试之前,您的被测数据库将处于您期望的状态。这样做的一个好处是无需回滚您的事务,但我已经使用内存中的 sqllite 运行了类似的测试,并且它可以正常工作。
于 2009-03-27T19:48:14.183 回答
1

检查connection.release_mode=on_close您的 SQLite NHibernate 配置中是否没有丢失。(参考文档

顺便说一句:总是处理你的ISessionISessionFactory.

于 2009-03-28T03:13:09.840 回答
0

抛弃 [Rollback] 并使用NDbUnit。我自己在这个确切的场景中使用它,它一直工作得很好。

于 2009-03-27T19:40:14.827 回答