有没有人对一致的多线程应用程序单元测试方法有任何建议?我做了一个应用程序,其中我们的模拟"工作线程"有一个thread.sleep,其时间由公共成员变量指定.我们将使用它,以便我们可以设置特定线程完成其工作所需的时间,然后我们可以执行我们的断言.有没有更好的方法来做到这一点?任何可以处理这个问题的.Net的好模拟框架?
第一步是要意识到,单元测试所需的大部分代码通常与线程正交.这意味着您应该尝试从执行线程的代码中分解执行工作的代码.完成后,您可以使用正常的单元测试实践轻松测试执行工作的代码.但是,当然,你知道这一点.
The problem is then one of testing the threading side of the problem but at least now you have a point where this threading interfaces with the code that does the work and hopefully you have an interface there that you can mock. Now that you have a mock for the code that the threading code calls into I find the best thing to do is add some events to the mock (this may mean you need to hand roll your mock). The events will then be used to allow the test to synchronise with and block the threading code under test.
因此,举例来说,假设我们有一些非常简单的东西,一个处理工作项的多线程队列.你要模拟工作项目.接口可能包含一个'Process()'方法,线程调用该方法来完成工作.你会在那里放两个事件.模拟在调用Process()时设置的模板和模拟在设置第一个事件后等待的模板.现在,在您的测试中,您可以启动队列,发布模拟工作项,然后等待工作项"我正在处理"事件.如果您正在测试的是该进程被调用,那么您可以设置另一个事件并让线程继续.如果你正在测试一些更复杂的东西,比如队列如何处理多个调度或者其他东西,那么在释放线程之前你可能会做其他的事情(比如发布和等待其他工作项).
我确定你的情况更复杂,但这是我用来测试线程代码的基本方法,它运行得很好.如果你模拟出正确的位并放入同步点,你可以对多线程代码进行惊人的控制.
这里有一些关于这种事情的更多信息,虽然它是在谈论C++代码库:http: //www.lenholgate.com/blog/2004/05/practical-testing.html
我的建议是不要依靠单元测试来检测并发问题,原因如下:
缺乏可重复性:测试只会偶尔失败一次,并且对确定问题没有多大帮助.
不稳定的失败构建会惹恼团队中的每个人 - 因为最后的提交总是被错误地怀疑是构建失败的原因.
遇到死锁可能会冻结构建,直到遇到执行超时,这会显着减慢构建速度.
构建环境可能是单个CPU环境(认为构建在VM中运行),其中并发问题可能永远不会发生 - 无论设置多少休眠时间.
它以某种方式打败了使用简单,隔离的验证代码单元的想法.
如果你必须测试后台线程做了什么,我发现一个简单的技术是使用WaitUntilTrue方法,它看起来像这样:
bool WaitUntilTrue(Funcfunc, int timeoutInMillis, int timeBetweenChecksMillis) { Stopwatch stopwatch = Stopwatch.StartNew(); while(stopwatch.ElapsedMilliseconds < timeoutInMillis) { if (func()) return true; Thread.Sleep(timeBetweenChecksMillis); } return false; }
像这样使用:
volatile bool backgroundThreadHasFinished = false; //run your multithreaded test and make sure the thread sets the above variable. Assert.IsTrue(WaitUntilTrue(x => backgroundThreadHasFinished, 1000, 10));
这样您就不必长时间睡眠主测试线程,以便让后台线程有时间完成.如果背景未在合理的时间内完成,则测试失败.
TypeMock(商业)有一个单元测试框架,可以自动尝试在多线程应用程序中查找死锁,我认为可以设置为运行具有可预测上下文切换的线程.
我本周在一个节目中看到了一个演示 - 显然它是在Alpha(称为Racer)
http://www.typemock.com/Typemock_software_development_tools.html