我有两个类,每个类都包含与数据库集成测试相关的内容。在每个类的构造函数中,我放置了一个重置数据库的方法:
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
我发现是在类的构造函数中调用的
CleanTables()
方法导致了这个问题。我猜测测试是并行运行的,并且两个类同时调用了CleanTables()
。因此,我尝试将CleanTables()
改为异步方法。public async Task<int> CleanTables() {
using(var conn = new SqlConnection("connStringHere")){
return await conn.Execute("someSqlCommandToCleanTables");
}
}
然后在类的构造函数中,我这样调用它:
public FirstClassSpec() {
var dataSetup = new DataSetup();
dataSetup.CleanTables().Wait();
}
public SecondClassSpec() {
var dataSetup = new DataSetup();
dataSetup.CleanTables().Wait();
}
但是现在当我尝试运行所有测试时,测试正在运行,但它们永远不会完成,我也无法得到结果。
我的问题是,死锁发生的原因是什么?为什么将 CleanTables()
方法改为异步会导致运行测试永远不会完成?我真的需要在每次运行测试之前清理表格。
----------------- 更新 -----------------------
我已经尝试为所有测试类添加了 [Collection["CollectionName"]]
,每个类都有不同的名称:
[Collection["FirstSpec"]]
public class FirstClassSpec {
//....
}
[Collection["SecondSpec"]]
public class FirstClassSpec {
//....
}
但是死锁仍然会发生...
----------------- 更新2 -----------------------
事实证明,具有相同集合名称的类将被顺序执行,这解决了死锁问题。