代码之家  ›  专栏  ›  技术社区  ›  Steve Dunn supercat

单元测试并发软件-你做什么?

  •  12
  • Steve Dunn supercat  · 技术社区  · 14 年前

    随着软件越来越并行,如何处理测试 类型的核心行为 使用单元测试(不是并行行为,只是核心行为)?

    在过去的好日子里,你有一个类型,你称它为,你检查它返回的内容和/或它调用的其他内容。

    现在,您调用一个方法,实际的工作被安排在下一个可用线程上运行;您不知道它何时实际开始并调用其他东西——而且,这些其他东西也可能是并发的。

    你怎么处理这个问题?您是否抽象/注入并发调度程序(例如,抽象任务并行库并在单元测试中提供一个假的/模拟)?

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


    编辑

    我已经编辑了这个问题,以强调测试类型的正常行为(忽略使用任何并行机制来利用多核,例如TPL)。


    6 回复  |  直到 13 年前
        1
  •  3
  •   Dror Helper    14 年前

    竞争条件和死锁的单元测试领域相对较新,缺乏良好的工具。

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

    另一种选择是尝试编写一个“压力测试”,它将导致死锁/争用条件浮出水面,创建多个实例/线程并并行运行它们。这种方法的缺点是,如果测试失败,就很难复制它。我建议在测试和生产代码中同时使用日志,这样您就能够理解发生了什么。

        2
  •  5
  •   GregC Benjamin Baumann    13 年前

    免责声明:我在科伦西克工作,一家西雅图的小公司。我们有一个叫做jinx的工具,它被设计用来检测代码中的并发错误。我们在测试版的时候现在是免费的,所以你可能想看看。( http://www.corensic.com/ )

    简言之,Jinx是一个非常瘦的管理程序,当被激活时,它会在处理器和操作系统之间滑动。然后,Jinx智能地获取执行切片并运行各种线程计时的模拟,以查找错误。当我们发现会导致错误发生的特定线程计时时,我们会在您的计算机上实现该计时“现实”(例如,如果您使用的是Visual Studio,调试器将在此时停止)。然后我们指出代码中导致错误的地方。Jinx没有假阳性。当它检测到一个错误时,它绝对是一个错误。

    Jinx可以在Linux和Windows上工作,也可以在本机代码和托管代码中工作。它与语言和应用程序平台无关,可以与所有现有工具一起工作。

    如果您查看了它,请向我们发送关于什么有效而什么无效的反馈。我们已经在一些大型开源项目上运行了Jinx,并且已经看到了这样的情况:Jinx发现bug的速度比简单的压力测试代码快50-100倍。

        3
  •  4
  •   Gishu    14 年前

    我建议取一份 Growing Object Oriented Software by Freeman and Pryce . 最后几章是非常有启发性的,并处理了这个具体的主题。它还引入了一些有助于确定符号以供讨论的术语。

    总结一下…… 他们的核心理念是 拆分功能和并发/同步方面 .

    • 弗斯特 试驾功能部件 在一个同步线程中,就像普通对象一样。
    • 一旦你的功能部分被固定下来。您可以转到并发方面。要做到这一点,你必须思考并提出 可观测不变量w.r.t.并发性 “对于您的对象,例如,计数应等于调用方法的次数。一旦确定了不变量,就可以编写运行多个线程的压力测试et.all来尝试破坏不变量。压力测试断言你的不变量。
    • 最后,作为一种额外的防御,运行工具或静态分析来查找错误。

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

    • 在收到预期通知之前,您可以阻止
    • 以合理的超时调查某些可观察到的副作用。
        4
  •  1
  •   RD1    14 年前

    我发现一种有用的技术是在一个检测竞争条件的工具(如IntelParallelInspector)中运行测试。测试运行要比正常慢得多,因为必须检查对时间的依赖性,但是一次运行可能会发现错误,否则将需要数百万次重复的正常运行。

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

        5
  •  0
  •   Leventix    14 年前

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

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

    黄瓜看起来像这样:

    When I press "Register"
    And the email sending script is run
    Then I should have an email
    
        6
  •  0
  •   Daniel    14 年前

    考虑到您的TPL将有自己的独立单元测试,您不需要验证这一点。

    假设我为每个模块编写两个测试:
    1)一个单线程单元测试,它使用一些环境变量或定义来转换TPL,以便我可以测试我的模块的功能正确性。
    2)以线程可展开模式运行模块的压力测试。这个测试试图发现并发性问题,应该使用大量随机数据。

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