xUnit测试死锁 [英] xUnit test deadlock

查看:72
本文介绍了xUnit测试死锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我运行xUnit单元测试时,有时在一个或多个测试中收到类似事务(进程ID 58)在另一个资源上与另一个进程在锁资源上被死锁,并被选择为死锁受害者"的错误消息.随机地.如果我自己重新运行任何失败的测试,它将通过.

我应该怎么做才能防止这种情况?是否可以选择一个接一个地运行测试,而不是一次运行?

(注:我正在Visual Studio 2015下通过ASP.Net 5 MVC控制器中的API方法运行测试)

以下是我偶尔失败的测试之一的示例:

 [Fact]
private void TestREAD()
{
    Linq2SQLTestHelpers.SQLCommands.AddCollections(TestCollections.Select(collection => Convert.Collection2DB(collection)).ToList(), TestSettings.LocalConnectionString);
    foreach (var testCollection in TestCollections)
    {
        var testCollectionFromDB = CollectionsController.Get(testCollection.Id);
        Assert.Equal(testCollection.Description, testCollectionFromDB.Description);
        Assert.Equal(testCollection.Id, testCollectionFromDB.Id);
        Assert.Equal(testCollection.IsPublic, testCollectionFromDB.IsPublic);
        Assert.Equal(testCollection.LayoutSettings, testCollectionFromDB.LayoutSettings);
        Assert.Equal(testCollection.Name, testCollectionFromDB.Name);
        Assert.Equal(testCollection.UserId, testCollectionFromDB.UserId);
    }
}
 

测试调用有两种方法,这是控制器方法:

 [HttpGet("{id}")]
public Collection Get(Guid id)
{
    var sql = @"SELECT * FROM Collections WHERE id = @id";
    using (var connection = new SqlConnection(ConnectionString))
    {
        var collection = connection.Query<Collection>(sql, new { id = id }).First();
        return collection;
    }
}
 

这是辅助方法:

 public static void AddCollections(List<Collection> collections, string connectionString)
{
    using (var db = new DataClassesDataContext(connectionString))
    {
        db.Collections.InsertAllOnSubmit(collections);
        db.SubmitChanges();
    }
}
 

(请注意,我在控制器方法中使用Dapper作为微型ORM,因此,为了避免在测试中重复出现错误,我在测试中使用LINQ to SQL来设置和清除-测试数据.)

在单元测试的类的构造函数和Dispose方法中也有数据库调用.如果需要,我可以将它们添加到帖子中.

解决方案

好的,看起来像是应用程序中常见的死锁情况,需要处理-应用程序方面的计划是什么?

测试及其数据绑定可能成为同一件事的牺牲品. xUnit没有任何可解决的问题,我强烈认为它不应该.

因此在测试和应用程序中,您都需要失败/重试管理.

对于Web应用程序,您可以向他们开除鲸鱼的图片,然后让他们重试图案,但最终您需要一个真正的解决方案.

要进行测试,您不想要鲸鱼,而且绝对想要处理它,即不易碎.

我将使用Poly将重试装饰包裹在应用程序或测试中容易出现重大故障的任何内容上–您的工作是弄清楚在您的上下文中什么是重大故障


在通常情况下,具有单个读取器/写入器同步运行的数据库不应死锁.分析发生这种情况的原因是在数据库方面进行分析.如果例如您的整体被测系统"具有某些方面,这导致了相互竞争的工作.

(显然,您的代码段是不完整的,因为CollectionsController.Get(testCollection.Id)与控制器方法不是static的事实之间存在脱节-尽管此讨论的重点不应该在IMO的那个级别上)

When I run my xUnit unit tests I sometimes get an error message like "Transaction (Process ID 58) was deadlocked on lock resources with another process and has been chosen as the deadlock victim" on one or more of the tests, seemingly randomly. If I re-run any failing test on its own it passes.

What should I do to prevent this? Is there an option to run the tests one-after-another instead of all at once?

(N.B. I'm running the tests over the API methods in my ASP.Net 5 MVC controllers under Visual Studio 2015)

Here's an example of one of my occasionally failing tests:

[Fact]
private void TestREAD()
{
    Linq2SQLTestHelpers.SQLCommands.AddCollections(TestCollections.Select(collection => Convert.Collection2DB(collection)).ToList(), TestSettings.LocalConnectionString);
    foreach (var testCollection in TestCollections)
    {
        var testCollectionFromDB = CollectionsController.Get(testCollection.Id);
        Assert.Equal(testCollection.Description, testCollectionFromDB.Description);
        Assert.Equal(testCollection.Id, testCollectionFromDB.Id);
        Assert.Equal(testCollection.IsPublic, testCollectionFromDB.IsPublic);
        Assert.Equal(testCollection.LayoutSettings, testCollectionFromDB.LayoutSettings);
        Assert.Equal(testCollection.Name, testCollectionFromDB.Name);
        Assert.Equal(testCollection.UserId, testCollectionFromDB.UserId);
    }
}

There are two methods the test calls, here's the controller method:

[HttpGet("{id}")]
public Collection Get(Guid id)
{
    var sql = @"SELECT * FROM Collections WHERE id = @id";
    using (var connection = new SqlConnection(ConnectionString))
    {
        var collection = connection.Query<Collection>(sql, new { id = id }).First();
        return collection;
    }
}

and here's the helper method:

public static void AddCollections(List<Collection> collections, string connectionString)
{
    using (var db = new DataClassesDataContext(connectionString))
    {
        db.Collections.InsertAllOnSubmit(collections);
        db.SubmitChanges();
    }
}

(Note that I'm using Dapper as the micro-ORM in the controller method and so, to avoid potentially duplicating errors in the test, I'm using LINQ to SQL instead in the test to set-up and clean-up test data.)

There are also database calls in the unit test's class's constructor and Dispose method. I can add them to the post if needed.

解决方案

OK, so looks like a plain vanilla case of deadlocks in your app and the need to handle that - what is your plan on the app side?

The tests and their data rigging can potentially fall prey to the same thing. xUnit doesnt have anything to address this and I'd strongly argue it shouldnt.

So in both the test and the app, you need failure/retry management.

For a web app, you have a fire them a picture of a whale and let them try again pattern but ultimately you want a real solution.

For a test, you don't want whales and definitely want to handle it, i.e. not be brittle.

I'd be using Poly to wrap retry decoration around anything in either the app or the tests that's prone to significant failures -- your exercise is to figure out what are the significant failures in your context.


Under normal circumstances a database with a single reader/writer operating synchronously shouldn't deadlock. Analysing why it happens is a matter of doing the analysis on the DB side. The tools that side would also likely quickly reveal to you if e.g. you have some aspect of your overall System Under Test which is resulting in competing work.

(Obviously your snippets are incomplete as there is a disconnect between CollectionsController.Get(testCollection.Id) and the fact that the controller method is not static - the point of this discussion should not be down at that level IMO though)

这篇关于xUnit测试死锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆