NUnit [TearDown]失败 - 哪个进程正在访问我的文件?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (104)

我有一个导致我悲伤的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;
}

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]时都会失败,所以我最终得到一个包含临时数据库文件的目录(每个测试一个,每个测试都有一个不同的名称)和一大堆失败的测试。

什么过程访问该文件?我不明白第二个进程如何访问该文件。在connection已经完全超出范围,并一直Dispose()方法由我试图删除文件时d,所以也不会有事的SQLite相关。它可以?

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

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

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

        }
    }
}

它没有任何区别--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);            

找到解决方案:

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

我通过调试器运行了单元测试,并且当[TearDown]方法启动时,肯定没有对SQLite DbConnection的引用。强制GC必须清理它们。SQLite中必须有一个bug。

提问于
用户回答回答于

尝试在dbconnection上调用Close

确保sqllite进程终止

你可以看到你的文件被Unlocker(免费)实用程序锁定了哪个进程

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

用户回答回答于

扫码关注云+社区

领取腾讯云代金券