12

随着软件变得越来越并发,如何用单元测试(而不是并行行为,只是核心行为)来处理类型的核心行为的测试单元测试并发软件 - 你做什么?

在过去的美好时光中,你有一种类型,你称之为,然后你检查它返回的内容和/或它调用的其他东西。

现在,你调用一个方法,实际的工作被安排在下一个可用的线程上运行;你不知道它什么时候才会开始并调用其他的东西 - 更重要的是,其他的东西也可能是并发的。

你如何处理这个问题?你是否抽象/注入并发调度器(例如抽象任务并行库并在单元测试中提供假/模拟)?

你遇到过哪些帮助你的资源?


编辑

我已经编辑强调测试类型的正常行为的问题(忽略任何并行机制用于采取多芯的优点,例如,TPL)


回答

3

对于竞态条件和死锁的单元测试领域是相对新的,缺乏好工具。

我知道无论是在早期的α/β阶段两个这样的工具:

另一种方法是尝试写一个“压力测试”,将导致死锁/比赛条件浮出水面,创建multiople实例/线程并且并行运行它们。这种做法的缺点是,如果测试失败,很难重现它。我建议在测试代码和生产代码中都使用日志,以便您能够理解发生的事情。

+0

感谢您的链接+1 - 我相信他们会派上用场,让任何人阅读这个问题。我编辑了我的问题,因为我真的打算多询问类型的正常行为而不是并发行为。 – 2010-07-29 16:02:20

0

单元测试确实不应该测试并发/异步行为,您应该在那里使用mocks并验证mock是否会收到预期的输入。

对于集成测试,我只是明确地调用后台任务,然后检查期望值。

在黄瓜它看起来像这样:

When I press "Register" 
And the email sending script is run 
Then I should have an email 
+0

好点 - 我不清楚我的问题,我指的是测试核心行为而不是平行行为。我编辑了这个问题。 – 2010-07-29 16:00:45

1

我发现有用的技术是检测像英特尔Parallel Inspector中的竞争条件的工具中运行测试。测试的运行速度比平时慢很多,因为必须检查时序依赖性,但一次运行可以发现错误,否则这些错误需要数百万次重复的普通运行。

我发现这非常有用,当转换现有的系统通过多核心的细粒度并行。

5

声明:我在西雅图的一家小型创业公司Corensic工作。我们有一个名为Jinx的工具,用于检测代码中的并发错误。现在我们处于测试阶段,这是免费的,所以您可能想要查看它。 (http://www.corensic.com/

简而言之,Jinx是一个非常薄的管理程序,在激活时会在处理器和操作系统之间滑动。然后Jinx智能地执行切片并运行各种线程时序的模拟以查找错误。当我们发现一个特定的线程时序会导致一个错误发生时,我们在你的机器上使这个时间“真实”(例如,如果你使用Visual Studio,那么调试器将在那一刻停止)。然后我们指出代码中导致错误的地方。 Jinx没有误报。当它检测到一个错误时,肯定是一个错误。

Jinx适用于Linux和Windows以及原生代码和托管代码。它是语言和应用程序平台不可知论的,并且可以与您现有的所有工具一起使用。

如果您检查出来,请发送给我们反馈什么有效和无效的反馈。我们已经在一些大型的开源项目上运行Jinx,并且已经看到Jinx能够比简单的压力测试代码快50-100倍的bug。

+0

这看起来非常有趣。并发问题可能需要几天甚至几个月才能找到,而像这样的机制来分析检测它们可能是非常有价值的。 – Cobusve 2016-09-23 22:36:06

0

鉴于您的TPL将有其独立的单元测试,您不需要验证。

鉴于我写为每个模块两个测试:
1),其使用某些环境变量或#定义打开TPL的,这样我可以测试我为功能正确性模块A单线程单元测试。
2)压力测试,以可线程部署模式运行模块。此测试尝试查找并发问题并应使用大量随机数据。

第二个测试通常包含许多模块,因此可能更多的是集成/系统测试。

4

我建议拿起Growing Object Oriented Software by Freeman and Pryce的副本。最后几章是非常有启发性的,并处理这个特定的主题。它还介绍了一些有助于确定讨论标记的术语。

总结.... 他们的核心思想是将拆分为功能和并发/同步方面

  • 首先试驾功能部分在像一个正常的对象的单个同步线程。
  • 将功能部件固定好后。您可以转到并发方面。要做到这一点,您必须考虑并为您的对象提供“可观察不变量w.r.t.并发”,例如,计数应该等于该方法被调用的次数。一旦确定了不变量,就可以编写运行多个线程的压力测试et.all来尝试和打破不变量。压力测试声明你的不变量。
  • 最后,为了增加防御,运行工具或静态分析来查找错误。

对于被动对象,即将从不同线程上的客户端调用的代码:您的测试需要通过启动自己的线程来模拟客户端。然后,您需要在通知侦听或采样/轮询方法之间进行选择,以便将测试与SUT同步。

  • 你既可以块,直到你收到预期的通知
  • 投票某些观察到的副作用有一个合理的超时。
相关问题