8

メッセージを受け取った後、それをエンキュー(テーブルに書き込む)するシステムがあり、別のプロセスがDBをポーリングし、処理のためにデキューします。自動テストでは、同じプロセスで操作をマージしましたが、(概念的には)2つの操作からの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");

テストの開始時(すべてのテスト)に、「静的」セッションプロバイダーをフェッチし、既存の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にプールされているので、次に作成するセッションには生成されたスキーマが表示されます。それでも、ほとんどの場合は機能しますが、受信メッセージのテーブルが表示されないため、後の「エンキュー」操作が失敗することがあります。また、これはテストスイートの実行ごとに最大1回または2回発生するようです。すべてのテストが失敗するわけではなく、最初のテストだけが失敗します(場合によっては別のテストも失敗します。2番目かどうかはよくわかりません)。

最悪の部分は、当然、ランダム性です。単に「失敗を止めた」という理由だけで、これを数回修正したと自分に言い聞かせました。無作為に。

これは、FW4.0、System.Data.SQLite x86バージョン、Win7 64bおよび2008R2(合計3つの異なるマシン)、FNHで構成されたNH2.1.2、TestDriven.NET32bプロセスおよびNUnitコンソール32bプロセスで発生します。

ヘルプ?

4

2 に答える 2

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

私の各統合テストはこのクラスを継承し、OpenSession() を呼び出してセッションを取得します。RecreateDB は、[SetUp] 属性のため、各テストの前に NUnit によって呼び出されます。

これが、このエラーが発生したあなたまたは他の誰かに役立つことを願っています.

于 2012-01-05T14:55:39.660 に答える
0

テスト後にランダムにセッションを開いたままにしているということだけが気になります。別の ISession を開く前に、既存の ISession が閉じていることを確認する必要があります。using() ステートメントを使用していないか、手動で Dispose() を呼び出していない場合、セッションはどこかでまだ生きている可能性があり、これらのランダムな例外が発生します。

于 2011-12-21T17:25:49.953 に答える