处理数据库上的数据时 xUnit Test 上的死锁

sam*_*vin 3 c# integration-testing database-connection xunit visual-studio-2015

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

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

为了运行 Visual Studio 2015 测试,我Run All TestsTest Explorer. 我收到了消息

事务(进程 ID {someID})与另一个进程在锁定资源上死锁

仅当我运行所有测试时才会出现此问题。如果我一个一个地运行每个测试或运行许多测试但来自同一个类,则永远不会发生死锁。我发现CleanTables()在类的构造函数中调用的方法导致了这个。我假设测试并行运行,并且CleanTables()被两个类同时调用。然后我尝试制作CleanTables()一个异步方法:

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

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

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

public SecondClassSpec() {
    var dataSetup = new DataSetup();
    dataSetup.CleanTables().Wait();
}
Run Code Online (Sandbox Code Playgroud)

但是现在当我尝试时Run All Tests,测试正在运行,但它们永远不会完成,我也永远不会得到结果。

我的问题是,为什么会发生死锁?为什么将CleanTables()方法更改为 async 会使正在运行的测试永远无法完成?我真的需要在每次测试运行之前清理表格。

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

我试过用 装饰所有的测试类[Collection["CollectionName"]],每个类都有不同的名称:

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

[Collection["SecondSpec"]]
public class FirstClassSpec {
    //....
}
Run Code Online (Sandbox Code Playgroud)

但是还是会出现死锁。。

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

原来具有相同集合名称的类将按顺序执行,这解决了死锁问题。

Mik*_*son 5

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

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