unit testingmultithreading应用程序?
有没有人有任何build议一致的方式来unit testingmultithreading应用程序? 我已经做了一个应用程序,我们的模拟“工作线程”有一个thread.sleep与一个公共成员variables指定的时间。 我们会使用这个,所以我们可以设置一个特定的线程将花费多长时间来完成它的工作,然后我们可以做我们的断言。 任何想法的更好的方法来做到这一点? 任何良好的模拟框架.NET可以处理这个?
我的build议不是依靠unit testing来检测并发问题,原因有几个:
- 缺乏可重复性:testing只会在一段时间内失败,并不能真正帮助找出问题。
- 不稳定的失败构build会使团队中的每个人都感到烦恼 – 因为最后一次提交将被错误地怀疑是造成失败的原因。
- 遇到死锁可能会冻结构build,直到遇到执行超时,这可能会显着减慢构build。
- 构build环境很可能是一个CPU环境(考虑在虚拟机中运行构build),而并发问题可能永远不会发生 – 无论设置了多lesshibernate时间。
- 它以某种方式击败了简单,孤立的validation代码单元的想法。
第一步是意识到通常unit testing所需的大部分代码都与线程正交。 这意味着你应该尝试分解线程代码来完成工作。 完成之后,您可以使用常规unit testing实践轻松testing执行该工作的代码。 但当然,你知道这一点。
然后问题是testing问题的线程端,但至less现在你有一个点,在这个线程接口与代码工作,希望你有一个接口,你可以模拟。 现在你已经对线程代码调用的代码进行了模拟,我发现最好的做法是向模拟中添加一些事件(这可能意味着你需要手动滚动你的模拟)。 这些事件将被用于允许testing与testing中的线程代码同步和阻塞。
所以,举个例子,可以说我们有一些非常简单的东西,一个处理工作项目的multithreading队列。 你会嘲笑工作项目。 该接口可能包含一个线程调用来执行工作的“Process()”方法。 你会在那里放两个事件。 一个是模拟在Process()被调用时设置的,另一个是在设置了第一个事件之后模拟器等待的。 现在,在你的testing中,你可以启动你的队列,发布一个模拟工作项目,然后等待工作项目的“我正在处理”事件。 如果你正在testing的是进程被调用,那么你可以设置其他事件,让线程继续。 如果你正在testing更复杂的东西,比如队列如何处理多个分派或者什么东西,那么在释放线程之前,你可能会做其他事情(比如发布和等待其他工作项目)。 既然你可以在testing中等待一段时间,你可以确保(比如说)只有两个工作项被并行处理,等等。关键是你使用线程代码阻塞的事件来确定testingtesting可以控制什么时候运行。
我相信你的情况更复杂,但这是我用来testing线程代码的基本方法,它工作得很好。 如果您嘲笑正确的位并放入同步点,您可以对multithreading代码进行令人惊讶的控制。
这里有一些关于这种事情的更多信息,尽pipe它是在讨论一个C ++代码库: http : //www.lenholgate.com/blog/2004/05/practical-testing.html
如果你不得不testing一个后台线程做些什么,我发现一个简单的方法是有一个WaitUntilTrue方法,看起来像这样:
bool WaitUntilTrue(Func<bool> func, 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));
这样你就不必长时间的睡眠你的主testing线程,从而让后台线程完成。 如果背景没有在合理的时间内完成,则testing失败。
TypeMock (商业)有一个unit testing框架,它自动地尝试findmultithreading应用程序中的死锁,我认为可以设置为运行具有可预测上下文切换的线程。
我在本周看到一个演示 – 显然是在Alpha(称为Racer)
http://www.typemock.com/Typemock_software_development_tools.html
我遇到了一个名为微软国际象棋的研究产品。 它专门devise用于multithreading应用程序的非确定性testing。 目前为止,它被集成到VS.
在多处理器机器上testingmultithreading代码是很重要的。 双核机器可能不够用。 我已经看到在双核单处理器上没有发生的4处理器机器上发生死锁。 然后,您需要基于客户端程序创build一个压力testing,该程序会产生许multithreading,并针对目标应用程序提出多个请求。 如果客户端机器是多处理器的话,它也会有所帮助,所以目标应用程序的负载更大。
我不认为unit testing是find线程错误的有效方法,但是它们可以是展示已知线程错误,隔离错误并testing修复错误的好方法。 我也用它们来testing我的应用程序中某些协调类的基本function,例如阻塞队列。
我将multithreadedTC库从Java移植到.NET,并将其称为TickingTest 。 它可以让你从一个unit testing方法启动几个线程并进行协调。 它没有原始的所有function,但我发现它很有用。 它最大的缺点是能够监视在testing过程中启动的线程。
不是一个unit testing,但你可以写一些testing代码,反复调用将在不同线程上执行的代码。 尝试在定期或最终一致性检查之间创build线程之间的最大交错。 当然这种方法有不可重现性的缺点,所以你需要使用大量的日志logging来判断出了什么问题。 这种方法最好与每个线程单个任务的unit testing相结合。
像GUIunit testing一样,这是一个自动化testing的滑铁卢。 真正的线程是根据定义..不可预知的..他们会干预不能预先确定的方式。 因此编写真正的testing是困难的,即使不是不可能
然而,你有一些这样的公司…我build议通过testing驱动雅虎组的档案。 我记得在附近的一些post.. 这是一个较新的。 (如果有人会善意地诽谤和转述,那就太好了,我太困了…需要这么做)