如何运行并发单元测试?
如何使用junit进行并发测试?
假设我有一个类,
public class MessageBoard
{
public synchronized void postMessage(String message)
{
....
}
public void updateMessage(Long id, String message)
{
....
}
}
我想同时测试对此 postMessage 的多个访问。 对此有什么建议吗? 我希望对我的所有 setter 函数(或任何涉及创建/更新/删除操作的方法)运行这种并发测试。
How to use junit to run concurrency test?
Let's say I have a class
public class MessageBoard
{
public synchronized void postMessage(String message)
{
....
}
public void updateMessage(Long id, String message)
{
....
}
}
I wan to test multiple access to this postMessage concurrently.
Any advice on this? I wish to run this kind of concurrency test against all my setter functions (or any method that involves create/update/delete operation).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
这里最好的方法是使用系统测试来用请求来爆破你的代码,看看它是否崩溃。 然后用单元测试来检查逻辑的正确性。 我解决这个问题的方法是为异步调用创建一个代理,并在测试下同步进行它。
但是,如果您想在完整安装和完整环境之外的级别执行此操作,您可以在 junit 中通过在单独的线程中创建对象来执行此操作,然后创建大量线程来向您的对象发出请求并阻止主线程直到完成。 如果你做得不对,这种方法可能会导致测试间歇性失败。
The best approach here is to use system tests to blast your code with requests to see if it falls over. Then use the unit test to check the logical correctness. The way i would approach this is create a proxy for the asynchronous call and have it made synchronously under test.
However, if you wanted to do this at a level other than a full install and complete environment you could do this in junit by creating your object in a separate thread, then create lots of threads that fire requests to your object and block the main thread until it completes. This approach can make tests fail intermittently if you don't get it right.
TestNG 支持 Java 并发测试。 这篇文章描述了如何使用它并且有文档在测试网站上。
但不确定是否可以同时进行相同的测试
TestNG has support for concurrency testing in Java. This article describes how it can be used and there is docs on the testng site.
Not sure if you can make the same test run at the same time though
您可以使用 tempus-fugit 库并行多次运行测试方法,以模拟负载测试类型环境。 尽管之前的评论指出 post 方法是同步的并因此受到保护,但可能涉及本身不受保护的关联成员或方法,因此加载/浸泡类型测试可能 抓住这些。 我建议您设置一个相当粗粒度/端到端的测试,以便为您提供捕获任何漏洞的最佳机会。
请参阅文档的 JUnit 集成部分。
顺便说一句,我是该项目的开发人员:)
You can use the tempus-fugit library to run test methods in parallel and multiple times to simulate a load testing type environment. Although a previous comment points out that the post method is syncrhonised and so protected, associated members or methods may be involved which themselves are not protected, so its possible that a load / soak type test could catch these. I'd suggest you setup a fairly coarse grained / end-to-end like test to give you the best chance of catching any loop holes.
See JUnit integration section of the documentation.
BTW, I a developer on said project :)
测试并发错误是不可能的; 您不仅需要验证输入/输出对,还必须验证测试期间可能发生或不发生的情况下的状态。 不幸的是 JUnit 不具备执行此操作的能力。
Testing concurrency bugs is impossible; you don't just have to validate input/output pairs, but you have to validate state in situations which may or may not occur during your tests. Unfortunately JUnit is not equipped to do this.
您还可以尝试 HavaRunner。 默认情况下它并行运行测试。
You can also try HavaRunner. It runs tests in parallel by default.
您只能证明并发错误的存在,而不能证明它们不存在。
但是,您可以编写一个专门的测试运行程序来生成多个并发线程,然后调用 @Test 注解的方法。
You can only prove the presence of concurrent bugs, not their absence.
However you can write a specialized test runner that spawns several concurrent thread and then calls your @Test annotated methods.
尝试查看 JUnit 附带的 ActiveTestSuite。 它可以同时启动多个 JUnit 测试:
上面将并行运行同一个 JUnit 测试类 5 次。 如果您希望并行测试有所变化,只需创建一个不同的类即可。
Try looking at ActiveTestSuite which ships with JUnit. It can concurrently launch multiple JUnit tests:
The above will run the same JUnit test class 5 times in paralell. If you wanted variation in your paralell tests, just create a different class.
在您的示例中,postMessage() 方法是同步的,因此您实际上不会看到单个虚拟机内的任何并发效果,但您也许能够评估同步版本的性能。
您将需要在不同的虚拟机中同时运行测试程序的多个副本。 使用
如果您无法让测试框架执行此操作,您可以 自己启动一些虚拟机。
流程构建器的东西对于路径之类的东西来说是一个痛苦,但这里是一般的草图:
我通常为简单的线程测试做这样的事情,就像其他人发布的那样,测试并不是正确性的证明,但它通常会消除愚蠢的错误在实践中。 它有助于在各种不同的条件下进行长时间的测试——有时并发错误需要一段时间才能在测试中显现出来。
In your example the postMessage() method is synchronized, so you won't actually see any concurrency effects from within a single VM but you might be able to evaluate the performance of the synchronized version.
You will need to run multiple copies of the test program at the same time in different VMs. You can use
If you can't get your test framework to do it you can launch some VMs your self.
The process builder stuff is a pain with paths and whatnot, but here is the general sketch:
I usually do something like this for simple threaded tests, like others have posted, testing is not a proof of correctness, but it usually shakes out silly bugs in practice. It helps to test for a long time under a variety of different conditions -- sometimes concurrency bugs take a while to manifest in a test.
同时运行可能会导致意外结果。 例如,我刚刚发现,虽然我的 200 个测试的测试套件在逐个执行时通过,但并发执行时失败,我发现这不是一个线程安全问题,而是一个依赖于另一个测试的测试,是一件坏事,我可以解决这个问题。
Mycila 在 JUnit ConcurrentJunitRunner 和 ConcurrentSuite 上的工作非常有趣。 与最新的 GA 版本相比,这篇文章似乎有点过时,在我的示例中我将展示更新的用法。
像下面这样注释测试类将导致同时执行测试方法,并发级别为 6:
您还可以同时运行所有测试类
: mycila/mycila-junit" rel="noreferrer">Maven 依赖项 是:
我目前正在研究如何与此包同时多次运行方法。 如果有人有一个例子让我知道,在我自制的解决方案下面,这可能已经是可能的。
正如其他人指出的那样,确实,您永远无法确定是否会出现并发错误,但如果执行数万或数十万次并发,例如 16,统计数据就在您这边。
Running concurrently can lead to unexpected results. For instance, I just discovered, that while my Test suite with 200 tests pass when executed one by one, it fails for concurrent execution, I dug that and it wasn't a thread safety problem, but a test depending on another one, which is a bad thing and I could solve the problem.
Mycila work on JUnit ConcurrentJunitRunner and ConcurrentSuite is very interesting. The article seems a little outdated compared to the latest GA release, in my examples I will show the updated usage.
Annotating a test class like the following will cause to execute test methods concurrently, with a concurrency level of 6:
You can also run all the test classes concurrently:
The Maven dependency is:
I am currently investigating how to run methods multiple times and concurrently with this package. It may be possible already, if anyone has an example let me know, below my homebrewed solution.
As others noted, is true that you can never be sure whether a concurrency bug would show up or not, but with ten of thousands, or hundred of thousands executions with a concurrency of, say 16, statistics is on your side.
在 .NET 中,有一些工具,例如 TypeMock Racer 或 Microsoft CHESS 专为单元测试并发性而设计。 这些工具不仅可以发现死锁等多线程错误,还可以为您提供重现错误的线程交错集。
我想 Java 世界也有类似的东西。
In .NET, there are tools like TypeMock Racer or Microsoft CHESS that are designed specifically for unit testing concurrency. These tools not only find multithreading bugs like deadlocks, but also give you the set of thread interleaves that reproduce the errors.
I'd imagine there's something similar for the Java world.
不幸的是,我不相信您可以通过使用运行时测试来明确证明您的代码是线程安全的。 您可以根据需要抛出任意数量的线程来反对它,并且它可能/可能不会通过,具体取决于调度。
也许您应该查看一些静态分析工具,例如 PMD,它可以确定您如何使用同步和识别使用问题。
Unfortunately I don't believe you can definitively prove that your code is thread-safe by using run-time testing. You can throw as many threads as you like against it, and it may/may not pass depending on the scheduling.
Perhaps you should look at some static analysis tools, such as PMD, that can determine how you're using synchronisation and identify usage problems.
我建议使用 MultithreadedTC - 由并发大师本人编写 比尔·普格(和 纳特·阿耶瓦)。 引用他们的概述:
该框架允许您在单独的测试中确定性地测试每个线程交错
I would recommend using MultithreadedTC - Written by the concurrency master himself Bill Pugh (and Nat Ayewah). Quote from their overview:
This framework allows you to deterministically test every thread interleaving in separate tests