处理数据库数据时 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
所以我有两个 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