当前位置:  开发笔记 > 前端 > 正文

单元测试多线程应用程序?

如何解决《单元测试多线程应用程序?》经验,为你挑选了4个好方法。

有没有人对一致的多线程应用程序单元测试方法有任何建议?我做了一个应用程序,其中我们的模拟"工作线程"有一个thread.sleep,其时间由公共成员变量指定.我们将使用它,以便我们可以设置特定线程完成其工作所需的时间,然后我们可以执行我们的断言.有没有更好的方法来做到这一点?任何可以处理这个问题的.Net的好模拟框架?



1> Len Holgate..:

第一步是要意识到,单元测试所需的大部分代码通常与线程正交.这意味着您应该尝试从执行线程的代码中分解执行工作的代码.完成后,您可以使用正常的单元测试实践轻松测试执行工作的代码.但是,当然,你知道这一点.

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



2> Joannes Verm..:

我的建议是不要依靠单元测试来检测并发问题,原因如下:

缺乏可重复性:测试只会偶尔失败一次,并且对确定问题没有多大帮助.

不稳定的失败构建会惹恼团队中的每个人 - 因为最后的提交总是被错误地怀疑是构建失败的原因.

遇到死锁可能会冻结构建,直到遇到执行超时,这会显着减慢构建速度.

构建环境可能是单个CPU环境(认为构建在VM中运行),其中并发问题可能永远不会发生 - 无论设置多少休眠时间.

它以某种方式打败了使用简单,隔离的验证代码单元的想法.


-1 - 我不同意,但后来我成功地使用单元测试来测试并发代码一段时间了.诀窍在于您从测试中控制测试代码的方式 - 请参阅我对原始问题的回复.恕我直言,你可以通过尝试使用单元测试来尽可能多地测试代码所面临的并发问题.它很难,它会让你对所测试的代码和一般的并发性都很认真; 其中,恕我直言是一件好事.
虽然这个建议可能是有效的,但它是"不做"的模板,它避开了应该做的事情.依赖于确定性单元测试(不应该具有线程时序或多组件依赖性)和彻底的多组件回归测试的组合.Len Holgate的答案为单元测试并发问题提供了一个很好的模板.
次要评论:有时可以编写单元测试来证明竞争条件/死锁.如果您可以在您(或所有者)修复代码之前执行此操作,那么您已帮助解释了该问题,并确保修复已足够.否则同意

3> Matt Howells..:

如果你必须测试后台线程做了什么,我发现一个简单的技术是使用WaitUntilTrue方法,它看起来像这样:

bool WaitUntilTrue(Func 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));

这样您就不必长时间睡眠主测试线程,以便让后台线程有时间完成.如果背景未在合理的时间内完成,则测试失败.


恕我直言,最好使用事件来同步和等待,而不是像那样旋转; 但我原则上同意.
为此,我使用`System.Threading.SpinWait.SpinUntil()`.

4> Lou Franco..:

TypeMock(商业)有一个单元测试框架,可以自动尝试在多线程应用程序中查找死锁,我认为可以设置为运行具有可预测上下文切换的线程.

我本周在一个节目中看到了一个演示 - 显然它是在Alpha(称为Racer)

http://www.typemock.com/Typemock_software_development_tools.html

推荐阅读
php
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有