在内存中的SQLite数据库中使用NHibernate进行测试时出现随机错误

Ari*_*elr 8 testing nhibernate system.data.sqlite in-memory

我有一个系统,它在收到消息后 - 将其排队(写入表),另一个进程轮询数据库并将其出列以进行处理.在我的自动测试中,我已经在同一个过程中合并了操作,但是不能(在概念上)合并来自两个操作的NH会话.

自然 - 出现问题.

我已经阅读了关于让SQLite-InMemory-NHibernate组合在测试环境中工作的一切,但由于"没有这样的表"错误,我现在遇到了随机测试失败.为了说清楚 - "随机"意味着具有相同确切配置和代码的相同测试有时会失败.

我有以下SQLite配置:

return SQLiteConfiguration
 .Standard
 .ConnectionString(x => x.Is("Data Source=:memory:; Version=3; New=True; Pooling=True; Max Pool Size=1;"))
 .Raw(NHibernate.Cfg.Environment.ReleaseConnections, "on_close");
Run Code Online (Sandbox Code Playgroud)

在我的测试开始时(每次测试),我获取"静态"会话提供程序,并请它刷新现有的数据库清理,并重新创建模式:

public void PurgeDatabaseOrCreateNew()
{
    using (var session = GetNewSession())
    using (var tx = session.BeginTransaction())
    {
            PurgeDatabaseOrCreateNew(session);
            tx.Commit();
    }
}

private void PurgeDatabaseOrCreateNew(ISession session)
{
    //http://ayende.com/Blog/archive/2009/04/28/nhibernate-unit-testing.aspx
    new SchemaExport(_Configuration)
        .Execute(false, true, false, session.Connection, null);
}
Run Code Online (Sandbox Code Playgroud)

所以是的,它是在不同的会话上,但是连接是在SQLite上汇集的,所以我创建的下一个会话将看到生成的模式.然而,虽然大多数时候它都有效 - 但有时后来的"入队"操作会失败,因为它无法看到我传入消息的表格.此外 - 每个测试套件运行似乎最多发生一次或两次; 并非所有的测试都失败了,只是第一个(有时是另一个.不太确定它是否是第二个).

最糟糕的是随机性,自然而然.我告诉自己我现在已经修好了几次,只是因为它只是"停止了失败".随意.

这种情况发生在FW4.0,System.Data.SQLite x86版本,Win7 64b和2008R2(总共三台不同的机器),NH2.1.2,配置了FNH,在TestDriven.NET 32b precesses和NUnit控制台32b进程上.

救命?

dvd*_*rle 8

嗨,我很确定我和你有完全相同的问题.我按照集成测试打开和关闭多个会话.在深入研究SQLite连接池和我自己的一些实验后,我得出以下结论:

SQLite池代码使用WeakReferences缓存连接,这不是缓存的最佳选择,因为当没有对连接的正常(强)引用并且GC运行时,将清除对连接的引用.由于无法预测GC的运行时间,因此可以解释"随机性".尝试GC.Collect();在关闭和打开另一个会话之间添加一个,您的测试将始终失败.

我的解决方案是在打开会话之间自己缓存连接,如下所示:

public class BaseIntegrationTest
{
    private static ISessionFactory _sessionFactory;
    private static Configuration _configuration;
    private static SchemaExport _schemaExport;

    // I cache the whole session because I don't want it and the
    // underlying connection to get closed.
    // The "Connection" property of the ISession is what we actually want.
    // Using the NHibernate SQLite Driver to get the connection would probably
    // work too.
    private static ISession _keepConnectionAlive;

    static BaseIntegrationTest()
    {
        _configuration = new Configuration();
        _configuration.Configure();
        _configuration.AddAssembly(typeof(Product).Assembly);
        _sessionFactory = _configuration.BuildSessionFactory();
        _schemaExport = new SchemaExport(_configuration);

        _keepConnectionAlive = _sessionFactory.OpenSession();
    }

    [SetUp]
    protected void RecreateDB()
    {
        _schemaExport.Execute(false, true, false, _keepConnectionAlive.Connection, null);
    }

    protected ISession OpenSession()
    {
        return _sessionFactory.OpenSession(_keepConnectionAlive.Connection);
    }
}
Run Code Online (Sandbox Code Playgroud)

我的每个集成测试都继承自这个类,并调用OpenSession()来获取会话.由于[SetUp]属性,在每次测试之前由NUnit调用RecreateDB.

我希望这可以帮助您或其他任何收到此错误的人.