处理数据库数据时 xUnit 测试死锁

Deadlock on xUnit Test when Processing Data on Database

所以我有两个 classes,每个都包含数据库集成测试。在每个 classes 的构造函数中,我放置了一个重置​​数据库的方法:

public class FirstClassSpec {
    public FirstClassSpec() {
        var dataSetup = new DataSetup();
        dataSetup.CleanTables();
    }

    [Fact]
    public async Task FirstTest() {
        using(var conn = new SqlConnection("connStringHere")){
            var result = await conn.ExecuteAsync("someSqlCommand");
            Assert.True(result > 0);
        }
    }
}

public class SecondClassSpec {
    public SecondClassSpec() {
        var dataSetup = new DataSetup();
        dataSetup.CleanTables();
    }

    [Fact]
    public async Task SecondTest() {
        using(var conn = new SqlConnection("connStringHere")){
            var result = await conn.ExecuteAsync("someSqlCommand");
            Assert.True(result > 0);
        }
    }
}

public class DataSetup {
    public void CleanTables() {
        using(var conn = new SqlConnection("connStringHere")){
            await conn.Execute("someSqlCommandToCleanTables");
        }
    }
}

为了 运行 测试 Visual Studio 2015,我在 Test Explorer 中使用 Run All Tests。我收到消息

Transaction (Process ID {someID}) was deadlocked on lock resources with another process

这个问题只有在我运行所有测试时才会发生。如果我 运行 每个测试一个接一个地测试,或者 运行 宁多个测试但来自同一个 class,死锁永远不会发生。 我发现在 classes 的构造函数中调用的 CleanTables() 方法导致了这个。我假设测试 运行 是并行的,并且 CleanTables() 被两个 class 同时调用。 所以我试着把 CleanTables() 变成一个异步方法:

public async Task<int> CleanTables() {
    using(var conn = new SqlConnection("connStringHere")){
        return await conn.Execute("someSqlCommandToCleanTables");
    }
}

然后在 classes 的构造函数上,我这样称呼它:

public FirstClassSpec() {
    var dataSetup = new DataSetup();
    dataSetup.CleanTables().Wait();
}

public SecondClassSpec() {
    var dataSetup = new DataSetup();
    dataSetup.CleanTables().Wait();
}

但现在当我尝试 Run All Tests 时,测试 运行ning 但它们从未完成,我也从未得到结果。

我的问题是,为什么会出现死锁?为什么将 CleanTables() 方法更改为异步方法会使 运行ning 测试永远无法完成?我真的需要在每次测试前清理表格 运行.

----------------更新-------------------- -

我尝试用 [Collection["CollectionName"]] 修饰所有测试 classes,每个 classes 都有不同的名称:

[Collection["FirstSpec"]]
public class FirstClassSpec {
    //....
}

[Collection["SecondSpec"]]
public class FirstClassSpec {
    //....
}

但是死锁还是出现了..

---------------- 更新 2 ---------------------- --

事实证明,具有相同集合名称的 classes 将按顺序执行,这解决了死锁问题。

您对 运行ning 并行测试的猜测是正确的。默认情况下,xUnit 不会 运行 在同一个 class 中并行测试。因此,要解决您的问题,您可以将所有测试移至一个 class。或者,您可以用 [Collection("My Collection")] 修饰 classes,以表明两个 classes 中的测试不应 运行 并行。

您可以在此处找到有关 xUnit 如何决定如何并行 运行 测试的更多信息:https://xunit.github.io/docs/running-tests-in-parallel.html