2011-04-14 49 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(),則會話可能仍然存在,導致這些隨機異常。

相關問題