NUnit [TearDown]失败 - 访问我的文件的进程是什么?

Ste*_*son 18 sqlite nunit unit-testing ioexception

最终编辑:我找到了问题的解决方案(在问题的底部).

我有一个让你感到悲伤的Nunit问题.编辑:实际上它看起来更像是一个SQLite问题,但我还不是100%肯定.

我的TestFixture有一个设置,可以生成一个随机文件名,在我的每个测试中都用作SQLite数据库.

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

我的每个测试都在访问数据库的每个方法中使用此构造:

[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;
}
Run Code Online (Sandbox Code Playgroud)

因此Connect()所有方法都使用了一个辅助方法.我假设using() { }构造Dispose()在结束时调用连接TestMethod()并释放与SQLite数据库文件的连接.

我遇到的问题是我的[TearDown]方法:

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

每次测试我都会得到一个例外:

System.IO.IOException: The process cannot access the file 'testdatabase2008-12-17_1030-04.614065.sqlite' because it is being used by another process.
Run Code Online (Sandbox Code Playgroud)

当他们到达[TearDown]时,所有测试都失败了,所以我最终得到一个充满临时数据库文件的目录(每个测试一个,每个都有不同的名称)和一大堆失败的测试.

访问文件的过程是什么?我不知道第二个进程如何访问该文件.在connection我尝试删除文件的时候,已经完全超出了范围并且已经是Dispose()d,因此它不能与SQLite相关.它可以?

请注意,如果我运行所有测试或只进行一次测试,我会得到相同的结果.

更新:所以我也试过Dispose()我的DbCommand对象,因为我没有这样做(我假设Dispose()DbConnection的所有其他ADO.NET提供程序也Dispose()s在该连接上的任何命令.)现在他们看起来像:

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

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它没有任何区别 - File.Delete()行仍然抛出IOException.:-(

如果我在[TearDown]中删除那一行,那么我的所有测试都会通过,但是我留下了一大堆临时数据库文件.

另一个更新: 这很好用:

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);            
Run Code Online (Sandbox Code Playgroud)

我不明白!

更新:找到解决方案:

    [TearDown]
    public void Cleanup()
    {
        GC.Collect();
        File.Delete(filename);
    }
Run Code Online (Sandbox Code Playgroud)

我通过调试器运行了单元测试,当[TearDown]方法启动时,肯定没有对SQLite DbConnection的引用了.强制GC必须清理它们.SQLite中必定存在错误.

fli*_*0de 8

感谢您在底部发布的答案.对于完全相同的情况,我正在挖掘数小时

GC.Collect ();
GC.WaitForPendingFinalizers ();
Run Code Online (Sandbox Code Playgroud)

做了伎俩.


Ste*_*owe 1

尝试在 dbconnection 上调用 Close

确保 sqllite 进程已终止

您可以使用 Unlocker(免费)实用程序查看哪个进程锁定了您的文件

这可能是SqlLite 的“已知”问题;论坛玩笑建议关闭连接并处理该命令,并建议这将在未来版本中修复(因为此行为与其他 ADO 提供程序不一致)