【问题标题】:Unit testing real-time / concurrent software [duplicate]单元测试实时/并发软件[重复]
【发布时间】:2010-12-16 13:12:56
【问题描述】:

可能重复:
How should I unit test threaded code?

经典的单元测试基本上只是将 x 放入并期望 y 输出,并使该过程自动化。因此,它适用于测试任何不涉及时间的事物。但是,我遇到的大多数重要错误都与时间有关。线程会破坏彼此的数据,或者导致死锁。发生不确定的行为——百万分之一。硬的东西。

对于多线程并发系统的“单元测试”部分有什么有用的吗?这样的测试是如何工作的?是否有必要长时间运行此类测试的主题并以某种巧妙的方式改变环境,以合理地确信它可以正常工作?

【问题讨论】:

    标签: java c++ c unit-testing concurrency


    【解决方案1】:

    这些天我所做的大部分工作都涉及多线程和/或分布式系统。大多数错误都涉及“happens-before”类型错误,其中开发人员假设(错误地)事件 A 总是在事件 B 之前发生。但程序每运行 1000000 次,事件 B 先发生,这会导致不可预测的行为。

    此外,实际上并没有任何好的工具来检测计时问题,甚至是由竞争条件引起的数据损坏。 Valgrind 工具包中的 Helgrind 和 drd 等工具非常适用于琐碎的程序,但它们在诊断大型复杂系统时并不是很有用。一方面,他们经常报告误报(尤其是 Helgrind)。另一方面,在 Helgrind/drd 下运行时,实际上很难检测到某些错误,因为在 Helgrind 下运行的程序运行速度几乎慢了 1000 倍,而且您经常需要运行一个程序很长时间才能重现 比赛条件。此外,由于在 Helgrind 下运行会完全改变程序的时序,因此可能不可能重现某个时序问题。这就是微妙的时间问题。从某种意义上说,他们几乎是海森堡式的,因为更改程序以检测时序问题可能会掩盖原始问题。

    可悲的事实是,人类仍然没有为处理复杂的并发软件做好充分准备。所以不幸的是,没有简单的方法对其进行单元测试。特别是对于分布式系统,您应该使用Lamport's happens-before diagrams 仔细规划您的程序,以帮助您确定程序中事件的必要顺序。但最终,您无法真正摆脱随机变化输入的蛮力单元测试。它还有助于在单元测试期间改变线程上下文切换的频率,例如运行另一个只占用 CPU 周期的后台进程。此外,如果您可以访问集群,则可以并行运行多个单元测试,这样可以更快地检测错误并节省大量时间。

    【讨论】:

    • 感谢您指出 Lamport 的图表!这些较新的“并发”语言通过专门使用不可变数据结构(例如 Clojure)来隐藏大部分时域的复杂性。但它们还不是万能的解决方案(目前)。
    • +1 仅仅因为这句话:“可悲的事实是,人类仍然没有为处理复杂的并发软件做好充分准备”,这让我想起了 Cooper 博士。
    【解决方案2】:

    如果您可以在 Linux 下运行测试,valgrind 包含一个名为 helgrind 的工具,该工具旨在检测使用 pthread 的程序中的竞争条件和潜在死锁;您可能会从运行多线程代码中获得一些好处,因为它会报告潜在的错误,即使它们实际上并没有在特定的测试运行中发生。

    【讨论】:

      【解决方案3】:

      我从来没有听说过什么可以。

      我猜如果有人要设计一个,它必须对线程的执行有精确的控制,并执行所有可能的线程步进组合。

      听起来像是一项重大任务,更不用说当有少数或更多线程时的数学组合......

      虽然,快速搜索一下stackoverflow...Unit testing a multithreaded application?

      【讨论】:

      • 呃,我想知道我怎么没有发现它。无论如何,它只提到了一个工具,它是用于 .NET 的,所以让我们等待 Java/C/C++ 是否有类似的东西。
      【解决方案4】:

      如果测试的系统足够简单,您可以通过阻止外部模型系统中的操作来很好地控制并发性。例如,可以通过等待一些其他操作开始来完成此阻塞。如果您可以控制所有外部调用,则可以通过实现不同的阻塞序列来很好地工作。我已经尝试过了,如果您非常了解可能有问题的序列,它确实可以很好地揭示锁级错误。与许多其他并发测试相比,它具有相当的确定性。然而,这种方法并不能很好地检测低级别的竞争条件。我通常只是去负载测试来找到那些,但我怀疑这不完全是单元测试。

      我已经看到了这些用于 .net 的并发测试框架,我认为有人为 Java 编写一个(希望如此)只是时间问题。

      不要忘记良好的旧代码阅读。查找并发错误的最佳方法之一是再次通读代码,全神贯注。

      【讨论】:

      • 毫无疑问,要想开发出 100% 正确的软件(无论是否并发),唯一的方法就是正确地做、仔细考虑、仔细检查等等。没有工具可以为您做到这一点。但在实践中,鉴于现实世界的限制以及我们都是人类,在并发软件等困难领域工作时,欢迎使用任何有用的工具。
      【解决方案5】:

      也许答案是您不应该这样做。在并发系统中,可能并不总是有一个正确的确定性答案。

      以人们登上火车并选择座位为例。每次你都会得到不同的结果。

      【讨论】:

      • 但肯定有不正确的答案,即使有不止一个正确答案。如果登机的人开始从火车座位上掉下来,这不是一个好结果:-)
      【解决方案6】:

      Awaitility 在您需要处理测试中的异步性时是一个有用的框架。它允许您等到系统中某处的某个状态被更新。例如:

      await().untilCall( to(myService).myMethod(), equalTo(3) );
      

      await().until( fieldIn(myObject).ofType(int.class), greaterThan(1));
      

      它还支持 Scala 和 Groovy。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多