随着软件越来越多并发,你如何使用单元测试来处理类型的核心行为(不是并行行为,只是核心行为)?
在过去的好时光中,你有一个类型,你打电话给它,你检查了它返回的内容和/或它所调用的其他内容。
现在,您调用一个方法,并且实际工作计划在下一个可用线程上运行;你不知道什么时候它会真正启动并调用其他东西 - 更重要的是,其他东西也可能是并发的。
你是如何处理的?你抽象/注入并发调度程序(例如抽象任务并行库并在单元测试中提供假/模拟)吗?
您遇到哪些资源帮助过您?
修改
我编辑了这个问题以强调测试该类型的正常行为(忽略用于利用多核的任何并行机制,例如TPL)
答案 0 :(得分:5)
免责声明:我在西雅图的一家小型创业公司Corensic工作。我们有一个名为Jinx的工具,用于检测代码中的并发错误。我们在测试阶段时它是免费的,所以你可能想要查看它。 (http://www.corensic.com/)
简而言之,Jinx是一个非常薄的虚拟机管理程序,在激活后,会在处理器和操作系统之间滑入。 Jinx然后智能地执行切片并运行各种线程计时的模拟以查找错误。当我们发现会导致错误发生的特定线程时序时,我们会在您的计算机上将该时间设置为“真实”(例如,如果您使用的是Visual Studio,则调试器将在此时停止)。然后,我们指出代码中导致错误的区域。 Jinx没有误报。当它检测到错误时,肯定是一个错误。
Jinx适用于Linux和Windows,以及本机代码和托管代码。它是语言和应用程序平台无关的,可以使用您现有的所有工具。
如果您查看,请向我们发送有关哪些有效且无效的反馈。我们已经在一些大型开源项目上运行Jinx,并且已经看到Jinx可以发现错误的速度比简单压力测试代码快50-100倍。
答案 1 :(得分:4)
我建议您选择Growing Object Oriented Software by Freeman and Pryce的副本。最后几章非常具有启发性并涉及这一特定主题。它还介绍了一些有助于确定讨论符号的术语。
总结...... 他们的核心思想是拆分功能和并发/同步方面。
对于被动对象,即从不同线程上的客户端调用的代码:您的测试需要通过启动自己的线程来模仿客户端。然后,您需要在通知监听或采样/轮询方法之间进行选择,以使您的测试与SUT同步。
答案 2 :(得分:3)
竞争条件和死锁的单元测试领域相对较新,缺乏良好的工具。
我知道早期alpha / beta阶段有两个这样的工具:
另一个选择是尝试编写一个“压力测试”,它会导致死锁/竞争条件浮出水面,创建多个实例/线程并将它们并排运行。这个问题的缺点是,如果测试失败,那么重现它将非常困难。我建议在测试和生产代码中使用日志,以便您能够理解发生了什么。
答案 3 :(得分:1)
我发现一种有用的技术是在检测竞争条件的工具中运行测试,例如Intel Parallel Inspector。测试运行速度比正常慢得多,因为必须检查对时间的依赖性,但是单次运行可以发现错误,否则将需要数百万次重复的普通运行。
我发现这在通过多核转换现有系统以实现细粒度并行时非常有用。
答案 4 :(得分:0)
单元测试确实不应该测试并发/异步行为,你应该在那里使用模拟并验证模拟是否接收到预期的输入。
对于集成测试,我只是明确调用后台任务,然后检查后面的期望。
在Cucumber中它看起来像这样:
When I press "Register"
And the email sending script is run
Then I should have an email
答案 5 :(得分:0)
鉴于您的TPL将有自己独立的单元测试,您无需验证。
鉴于我为每个模块编写了两个测试:
1)单线程单元测试,使用一些环境变量或#define来转换TPL,以便我可以测试我的模块的功能正确性。
2)压力测试,以线程可部署模式运行模块。此测试尝试查找并发问题,并应使用大量随机数据。
第二个测试通常包括许多模块,因此可能更多的是集成/系统测试。