Java 实时/并发软件的单元测试

Java 实时/并发软件的单元测试,java,c++,c,unit-testing,concurrency,Java,C++,C,Unit Testing,Concurrency,可能重复: 经典的单元测试基本上就是输入x,输出y,然后自动化这个过程。因此,它适合于测试任何不需要时间的东西。但是,我遇到的大多数重要bug都与时间有关。线程损坏彼此的数据,或导致死锁。不确定性行为发生在百万分之一的时间内。硬东西 对于多线程并发系统的“单元测试”部分,有什么有用的东西吗?这些测试是如何工作的?是否有必要长时间运行此类测试的主题,并以某种巧妙的方式改变环境,从而合理地确信它可以正常工作?我从未听说过任何可以这样做的事情 我想如果有人要设计一个,它必须对线程的执行进行精确的控制

可能重复:

经典的单元测试基本上就是输入x,输出y,然后自动化这个过程。因此,它适合于测试任何不需要时间的东西。但是,我遇到的大多数重要bug都与时间有关。线程损坏彼此的数据,或导致死锁。不确定性行为发生在百万分之一的时间内。硬东西


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

我从未听说过任何可以这样做的事情

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

听起来像是一项主要任务,更不用说当有少量或更多线程时,非平凡大小的线程的数学组合了


虽然,快速搜索stackoverflow

如果您可以在Linux下运行测试,valgrind包括一个名为的工具,该工具旨在检测使用pthreads的程序中的竞争条件和潜在死锁;在这种情况下运行多线程代码可能会给您带来一些好处,因为它会报告潜在的错误,即使这些错误在特定的测试运行中没有实际发生。

如果测试系统足够简单,您可以通过阻止外部模拟系统中的操作来很好地控制并发性。例如,可以通过等待其他操作启动来完成此阻塞。如果您可以控制所有外部调用,那么通过实现不同的阻塞序列,这可能会非常有效。我已经试过了,如果您对可能出现的问题序列了如指掌的话,它确实很好地揭示了锁级错误。与许多其他并发测试相比,它是非常确定的。然而,这种方法不能很好地检测低水平的竞争条件。我通常只是通过负载测试来找到这些,但我认为这并不完全是单元测试

我看过这些针对.net的并发测试框架,我认为在有人为Java编写一个框架之前,这只是时间问题(希望如此)


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

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

此外,还没有任何好的工具来检测计时问题,甚至检测由竞争条件导致的数据损坏。Valgrind工具箱中的Helgrind和drd等工具对于简单的程序非常有用,但它们在诊断大型复杂系统时用处不大。首先,他们经常报告假阳性(尤其是Helgrind)。另一方面,在Helgrind/drd下运行时很难检测到某些错误,因为在Helgrind下运行的程序运行速度慢了近1000倍,而且您通常需要运行一个程序相当长的时间才能重现比赛状态。此外,由于在Helgrind下运行会完全改变程序的计时,因此可能无法重现某个计时问题。这就是微妙的时间问题;他们几乎是海森伯吉人,因为改变一个程序来检测时间问题可能会掩盖原来的问题


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

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

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

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

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


它还支持Scala和Groovy。

嗯,我想知道我怎么没有发现它。无论如何,它只提到了一个工具,它是用于.NET的,所以让我们等待Java/C/C++是否有类似的工具。要想得到100%正确的软件(并发或不并发),唯一的方法就是正确地做,仔细考虑,仔细检查,等等。没有工具可以帮你。但在实践中,考虑到现实世界的限制以及我们都是人,在并发软件等困难领域工作时,欢迎使用任何有用的工具。感谢您指出兰波特的图表!有一些较新的“并发”语言专门使用不可变的数据结构(例如Clojure),从而隐藏了时域的许多复杂性。但是他们还没有完全解决所有问题。+1仅仅是因为这句话:“可悲的事实是,人类还没有充分准备好应对wi
await().until( fieldIn(myObject).ofType(int.class), greaterThan(1));