19

最終編集:問題の解決策を見つけました(質問の下部にあります)。

私は悲しみを引き起こしているNunitの問題を抱えています。編集:実際にはSQLiteの問題のように見えますが、まだ100%確実ではありません。

私のTestFixtureには、各テストでSQLiteデータベースとして使用されるランダムなファイル名を生成する設定があります。

[Setup]
public void Setup()
{
    // "filename" is a private field in my TestFixture class
    filename = ...; // generate random filename
}

私の各テストでは、データベースにアクセスする各メソッドでこの構成を使用しています。

[Test]
public void TestMethod()
{
    using (var connection = Connect())
    {
        // do database activity using connection

        // I've tried including this line but it doesn't help
        // and is strictly unnecessary:
        connection.Close();
    }
}

private DbConnection Connect()
{
    var connection = DbProviderFactories.GetFactory("System.Data.SQLite").CreateConnection();
    connection.ConnectionString = "Data Source=" + filename;
    connection.Open();
    return connection;
}

そのため、1つのヘルパーメソッドConnect()がすべてのメソッドで使用されます。using() { }コンストラクトがDispose()最後に接続を呼び出しTestMethod()、SQLiteデータベースファイルへの接続を解放していると想定しています。

私が抱えている問題は、[TearDown]メソッドにあります。

    [TearDown]
    public void Cleanup()
    {
        File.Delete(filename); // throws an IOException!
    }

すべてのテストで例外が発生します。

System.IO.IOException: The process cannot access the file 'testdatabase2008-12-17_1030-04.614065.sqlite' because it is being used by another process.

[TearDown]に到達すると、すべてのテストが失敗するため、一時的なデータベースファイル(テストごとに1つ、それぞれ異なる名前)でいっぱいのディレクトリと、失敗したテストがたくさんあります。

どのプロセスがファイルにアクセスしていますか?2番目のプロセスがファイルにアクセスする方法がわかりません。はconnection完全にスコープ外になり、ファイルを削除しようとしている時点でDispose()されているため、SQLiteに関連するものにすることはできません。それをできる?

すべてのテストを実行した場合、または1つのテストだけを実行した場合でも、同じ結果が得られることに注意してください。

更新:それで、DbCommandオブジェクトのDispose()も試していませんでした(DbConnectionをDispose()する他のすべてのADO.NETプロバイダーもその接続上のコマンドをDispose()すると仮定しました) 。)これで、次のようになります。

[Test]
public void TestMethod()
{
    using (var connection = Connect())
    {
        using (var command = connection.CreateCommand())
        {
        // do database activity using connection

        }
    }
}

違いはありませんでした。File.Delete()行は引き続きIOExceptionをスローします。:-(

[TearDown]でその1行を削除すると、すべてのテストに合格しますが、大量の一時データベースファイルが残ります。

別の更新: これは問題なく機能します:

var filename = "testfile.sqlite";
using (var connection = BbProviderFactories.GetFactory("System.Data.SQLite").CreateConnection())
{
    connection.ConnectionString = "Data Source=" + filename;
    connection.Open();
    var createCommand = connection.CreateCommand();
    createCommand.CommandText =
        "CREATE TABLE foo (id integer not null primary key autoincrement, bar text not null);";
    createCommand.ExecuteNonQuery();
    var insertCommand = connection.CreateCommand();
    insertCommand.CommandText = "INSERT INTO foo (bar) VALUES (@bar)";
    insertCommand.Parameters.Add(insertCommand.CreateParameter());
    insertCommand.Parameters[0].ParameterName = "@bar";
    insertCommand.Parameters[0].Value = "quux";
    insertCommand.ExecuteNonQuery();
}
File.Delete(filename);            

理解できない!

更新:解決策が見つかりました:

    [TearDown]
    public void Cleanup()
    {
        GC.Collect();
        File.Delete(filename);
    }

デバッガーを介して単体テストを実行しましたが、[TearDown]メソッドが開始されると、SQLiteDbConnectionへの参照はなくなりました。ただし、GCを強制するとそれらをクリーンアップする必要があります。SQLiteにバグがあるはずです。

4

11 に答える 11

9

下部に投稿された回答をありがとう。私はまったく同じケースで何時間も掘っていました

GC.Collect ();
GC.WaitForPendingFinalizers ();

トリックをしました。

于 2012-09-14T11:58:07.170 に答える
1

dbconnection で Close を呼び出してみてください

sqlliteプロセスが終了していることを確認してください

Unlocker (無料) ユーティリティを使用して、ファイルがロックされているプロセスを確認できます

これはSqlLite の「既知」の問題である可能性があります。フォーラムの冗談は、接続を閉じてコマンドを破棄することを提案し、これは将来のバージョンで修正されることを示唆しています (この動作は他の ADO プロバイダーと一致していないため)。

于 2008-12-17T13:54:54.010 に答える
1

静的メソッドを呼び出す

SqliteConnection.ClearAllPools()

この呼び出しの後、データベース ファイルのロックが解除され、[TearDown] でファイルを削除できます。

于 2010-10-21T19:14:04.107 に答える
1

この答えが1年以上遅れていることは知っていますが、将来読む人にとっては...

私はあなたと同様の問題を抱えていました.SQLiteデータベースファイルが開いたままになっているため、テストの間にテストデータベースを削除しようとして失敗しました。コードの問題を追跡して、SQLiteDataReader オブジェクトが明示的に閉じられていないことを突き止めました。

SQLiteDataReader dr = cmd_.ExecuteReader();
while (dr.Read())
{
    // use the DataReader results
}
dr.Close();  //  <-- necessary for database resources to be released
于 2010-01-25T11:50:00.207 に答える
0

アンチウイルスを実行していますか?一部のAV製品は、ファイルが閉じられていることを確認するとファイルをスキャンします。削除しようとしたときにAVソフトウェアがまだファイルを開いている場合は、この問題が発生します。少し遅れて削除を再試行できます。

これは検索インデクサーでも発生します。

于 2008-12-17T15:36:54.413 に答える
0

ティアダウンは、各テストの後に実行されます。

この属性は TestFixture 内で使用され、各テスト メソッドの実行後に実行される関数の共通セットを提供します。

TestFixtureTearDownでそれらをすべて削除してみてください:

    [TestFixtureTearDown]
    public void finish()
    {
        //Delete all file
    }

あるテストが、別のテストで削除しようとしているファイルを使用している可能性があります。 <-- [Stewart] 質問で述べたように、テストを 1 回だけ実行したときに発生するため、これは不可能です。

更新 あなたは自分がしていることについて十分な情報を提供していません。テスト ファイル内のテストを 1 つだけにして、すべてのテスト ファイルをクリーンアップして試してみましたか? [スチュワート] はい。[Stewart]が機能する場合(機能しない場合)、複数のテストに問題があります (相互にアクセスします)。ソースを見つけるには、問題を切り詰める必要があります。それから、ここに戻ってきてください。私たちがお手伝いします。現時点では、私たちがあなたに与えることができるのは推測だけです. [Stewart] 私はあなたが提案した問題のこれらのカットダウンをすでに行っています。あなたはそれらが私の最初の質問にあることがわかるでしょう!

于 2008-12-17T14:07:45.077 に答える
0

データベースを開くために何を使用しますか? ここから ADO 2.0 コネクタを使用しますか。それを使用するアプリケーションがあり、それを使用して複数の接続を行うことができる場合(閉じる/開く)。このコネクタを使用していない場合は、試してみてください。メソッド Connect() は何を返しますか?

于 2008-12-17T16:58:11.427 に答える
0

ファイル名の作成ロジックを確認する必要がありますが、ファイルを開いて作成しているが、作成後に閉じていない可能性があります。System.IO.Path.GetTempFileName() を使用すると、ファイルが作成され、ファイルが閉じられた状態でファイルの名前が返されると思います。独自のランダムな名前生成を行い、File.Open を使用している場合は、後で閉じていることを確認する必要があります。

別の注意として、単体テストで実際のデータベースから読み書きするのではなく、データベースを抽象化するモッキング戦略を追求することを心からお勧めします。単体テストのポイントは、非常に高速である必要があり、ファイル I/O によってこれらの速度が大幅に低下することです。

于 2008-12-17T14:52:48.963 に答える
0

最初のステップは、問題のファイルへのハンドルを保持している人を見つけることです。

Process Explorerのコピーを入手して実行します。Ctrl+F を押して、ファイルの名前を入力します。アクセスしているプロセスのリストが表示されます。

于 2008-12-17T15:50:02.687 に答える
0

ファイルが閉じられている可能性はありますか (つまり、SQLLite はファイルをすぐに解放しません)?

データベースを遅延ループ (各試行の間に 1 秒程度) に入れて、ループを数回 (5 回程度) 繰り返した後にのみ例外をスローしてみてください。

于 2008-12-17T16:44:43.573 に答える