2011-04-14 61 views
8

我有一个系统,它获得一条消息后 - 入队(写入一个表),另一个进程轮询数据库并将其出队处理。在我的自动测试中,我已经将操作合并到同一个进程中,但不能(从概念上)合并来自两个操作的NH会话。在内存中SQLite数据库测试NHibernate时出现随机错误

自然 - 出现问题。

我已经阅读了所有关于让SQLite-InMemory-NHibernate组合在测试世界中工作的所有内容,但由于“没有这样的表”错误,我现在已经遇到了RANDOMLY失败的测试。要说清楚 - “随机”意味着具有相同确切配置和代码的相同测试有时会失败。

我有以下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"); 

在我的测试(每个测试)我取“静”会话提供的开始,并恳请它刷新现有DB干净,并重新创建模式:

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

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

最糟糕的部分是随机性,自然。我告诉自己我现在已经修好几次了,只是因为它只是“停止失败”。随机。

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

帮助?

+0

我也有这个问题。几乎每个测试都通过了,但偶尔有一两次测试会失败,并显示“没有这样的表”错误,如果我再次运行它们,它们会通过。我认为这只是SQLite在随机重新创建连接池中的连接。 – 2011-08-31 12:33:56

回答

8

嗨,我很确定我有和你一样的问题。我为每个集成测试打开和关闭多个会话。通过SQLite的连接池和我自己的一些试验挖后,我得出了以下结论:

SQLite的池代码使用在WeakReferences缓存的连接,这是不用于缓存的最佳option,由于基准如果没有正常(强烈)的连接参考和GC运行,连接将被清除。由于无法预测GC何时运行,因此这解释了“随机性”。尝试添加一个GC.Collect();关闭一个和打开另一个会话之间,你的测试总是失败。

我的解决办法是缓存连接自己的开幕式上之间,就像这样:

我integrationtests的
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); 
    } 
} 

每个从这个类继承,并调用的openSession()来获取会话。由于[SetUp]属性,在每次测试之前,由NUnit调用RecreateDB。

我希望这可以帮助你或任何其他人谁得到这个错误。

+0

更改SQLite的缓存机制可能会是最清洁的解决方案,但我还没有信心做到这一点;-) – dvdvorle 2012-01-05 15:02:16

+0

这正是我解决它的方法。对不起,没有提前发布解决方案。 – Arielr 2012-01-06 09:29:11

0

唯一让我们想到的是,你在测试后随机离开会话。在打开另一个ISession之前,您必须确保已有的ISession已关闭。如果您没有使用using()语句或手动调用Dispose(),则会话可能仍然存在,导致这些随机异常。

相关问题