我是单元测试和 nUnit (2.48) 的新手。我想写一个测试方法,失败的情况是它死锁。这可能吗?显然,nUnit 默认情况下不知道该方法应该执行多长时间,所以我是否必须编写代码在单独的线程上完成工作,然后如果它花费的时间超过我定义的时间,则中止它并抛出异常?有一个更好的方法吗?
谢谢
我是单元测试和 nUnit (2.48) 的新手。我想写一个测试方法,失败的情况是它死锁。这可能吗?显然,nUnit 默认情况下不知道该方法应该执行多长时间,所以我是否必须编写代码在单独的线程上完成工作,然后如果它花费的时间超过我定义的时间,则中止它并抛出异常?有一个更好的方法吗?
谢谢
当然可以通过在另一个线程上运行代码并查看它是否及时返回来测试死锁。这是一些(非常基本的)示例代码:
[TestFixture]
public class DeadlockTests
{
[Test]
public void TestForDeadlock()
{
Thread thread = new Thread(ThreadFunction);
thread.Start();
if (!thread.Join(5000))
{
Assert.Fail("Deadlock detected");
}
}
private void ThreadFunction()
{
// do something that causes a deadlock here
Thread.Sleep(10000);
}
}
我不想说这是“最好的方法”,但我发现它有时很有用。
这是可能的,但它可能不是最好的做法。单元测试并不真正适合测试并发行为,不幸的是没有很多适合的测试方法。
NUnit 不对线程做任何事情。您可以编写启动多个线程的测试,然后测试它们的交互。但是这些看起来更像是集成测试而不是单元测试。
另一个问题是死锁行为通常取决于线程调度的顺序。因此很难编写一个结论性的测试来测试某个死锁问题,因为您无法控制线程调度,这是由操作系统。您最终可能会遇到有时在多核处理器上失败但在单核处理器上总是成功的测试。
死锁检测相当于停机问题,因此目前一般情况下无法解决。
如果您有特定的问题需要防范,那么可能会有特定的黑客攻击来获得至少一点安全性。但请注意,这只能是一种黑客行为,而永远不会 100%。例如,这样的测试可能总是在开发机器上通过,但永远不会在生产机器上通过。
看看名为“国际象棋”的微软项目。它旨在查找并发错误http://research.microsoft.com/en-us/projects/chess/
要测试死锁,您必须在单元测试中实现状态图并检查当前状态图中的循环。状态图由作为节点的资源和作为边的依赖关系组成。我不知道这样的事情的实现,但这就是理论。
单元测试测试数据输入和输出的正确性(主要用于后面一点),而不是测试应用程序执行流程的正确性。
Mark Heath 的想法看似合理,但在学术上是错误的。