Unit testing 如何运行并发单元测试?
如何使用junit运行并发测试 假设我有一节课Unit testing 如何运行并发单元测试?,unit-testing,concurrency,junit,Unit Testing,Concurrency,Junit,如何使用junit运行并发测试 假设我有一节课 public class MessageBoard { public synchronized void postMessage(String message) { .... } public void updateMessage(Long id, String message) { .... } } 我想同时测试对这个postMessage的多重访问。 有什么建议
public class MessageBoard
{
public synchronized void postMessage(String message)
{
....
}
public void updateMessage(Long id, String message)
{
....
}
}
我想同时测试对这个postMessage的多重访问。
有什么建议吗?我希望对我的所有setter函数(或涉及创建/更新/删除操作的任何方法)运行这种并发测试。不幸的是,我不相信您可以通过运行时测试来最终证明您的代码是线程安全的。您可以对它抛出任意多个线程,根据调度情况,它可能会通过,也可能不会通过
也许您应该看看一些静态分析工具,例如,它们可以确定您如何使用同步并识别使用问题。您只能证明并发错误的存在,而不能证明它们的缺失 但是,您可以编写一个专门的测试运行程序,生成几个并发线程,然后调用@test注释的方法 支持Java中的并发测试。这描述了如何使用它,testng站点上有文档
不确定是否可以在同一时间运行相同的测试,不过这里最好的方法是使用系统测试在请求中对代码进行爆破,以查看代码是否失效。然后使用单元测试来检查逻辑正确性。我的方法是为异步调用创建一个代理,并让它在测试中同步进行
但是,如果您想在完全安装和完整环境之外的级别执行此操作,您可以在junit中通过在单独的线程中创建对象来执行此操作,然后创建大量线程,向对象发出请求并阻止主线程,直到它完成。这种方法可能会使测试间歇性地失败,如果你做得不对。在.NET中,有一些工具,如或,专门为单元测试并发性而设计。这些工具不仅可以找到死锁之类的多线程错误,还可以为您提供一组重现错误的线程交错
我想Java世界也有类似的情况。在您的示例中,postMessage()方法是同步的,因此您实际上不会在单个VM中看到任何并发效果,但您可以评估同步版本的性能 您需要在不同的VM中同时运行测试程序的多个副本。你可以用 如果你不能让你的测试框架去做,你可以自己启动一些虚拟机。 process builder的东西对于路径之类的东西来说是一件痛苦的事情,但这里是一个大致的示意图:
Process running[] = new Process[5];
for (int i = 0; i < 5; i++) {
ProcessBuilder b = new ProcessBuilder("java -cp " + getCP() + " MyTestRunner");
running[i] = b.start();
}
for(int i = 0; i < 5; i++) {
running[i].waitFor();
}
进程运行[]=新进程[5];
对于(int i=0;i<5;i++){
ProcessBuilder b=newProcessBuilder(“java-cp”+getCP()+“MyTestRunner”);
运行[i]=b.start();
}
对于(int i=0;i<5;i++){
正在运行[i].waitFor();
}
我通常为简单的线程测试做类似的事情,就像其他人发布的一样,测试不是正确性的证明,但它通常会在实践中消除愚蠢的错误。它有助于在各种不同的条件下进行长时间的测试——有时并发错误需要一段时间才能在测试中表现出来
public void testMesageBoard() {
final MessageBoard b = new MessageBoard();
int n = 5;
Thread T[] = new Thread[n];
for (int i = 0; i < n; i++) {
T[i] = new Thread(new Runnable() {
public void run() {
for (int j = 0; j < maxIterations; j++) {
Thread.sleep( random.nextInt(50) );
b.postMessage(generateMessage(j));
verifyContent(j); // put some assertions here
}
}
});
PerfTimer.start();
for (Thread t : T) {
t.start();
}
for (Thread t : T) {
t.join();
}
PerfTimer.stop();
log("took: " + PerfTimer.elapsed());
}
}**strong text**
public void testMesageBoard(){
最终留言板b=新留言板();
int n=5;
螺纹T[]=新螺纹[n];
对于(int i=0;i
测试并发错误是不可能的;您不仅需要验证输入/输出对,还必须在测试期间可能发生或不发生的情况下验证状态。不幸的是,JUnit无法做到这一点。我建议使用并发主机自己编写的-和。引述他们的话:
多线程的EDTC是一个
测试并发应用程序。信息技术
功能节拍器,用于
提供对序列的精细控制
在多个线程中对活动进行排序
此框架允许您在单独的测试中确定地测试每个交错线程您可以使用tempus fugit库并行运行测试方法,并多次运行测试方法,以模拟负载测试类型的环境。尽管之前的评论指出,post方法是同步的,因此受到保护,但可能涉及到自身未受保护的相关构件或方法,因此负载/浸泡类型测试可能会捕捉到这些构件或方法。我建议您设置一个相当粗粒度的/端到端的测试,以使您获得捕获任何循环漏洞的最佳机会 请参阅的JUnit集成部分
顺便说一句,我是上述项目的开发人员:)试着看看JUnit附带的ActiveTestSuite。它可以同时启动多个JUnit测试:
public static Test suite()
{
TestSuite suite = new ActiveTestSuite();
suite.addTestSuite(PostMessageTest.class);
suite.addTestSuite(PostMessageTest.class);
suite.addTestSuite(PostMessageTest.class);
suite.addTestSuite(PostMessageTest.class);
suite.addTestSuite(PostMessageTest.class);
return suite;
}
以上内容将并行运行同一JUnit测试类5次。如果您想要并行测试中的变化,只需创建一个不同的类。并发运行可能会导致意外的结果。例如,我刚刚发现,虽然我的测试套件有200个测试,在逐个执行时通过,但并发执行失败,我发现这不是线程安全问题,而是依赖于另一个测试的测试,这是一件坏事,我可以解决问题 这很有趣。与最新的GA版本相比,本文似乎有点过时,在我的示例中,我将展示更新的用法 按如下方式注释测试类将导致并发执行测试方法,并发级别为6:
import com.mycila.junit.concurrent.ConcurrentJunitRunner;
import com.mycila.junit.concurrent.Concurrency;
@RunWith(ConcurrentJunitRunner.class)
@Concurrency(6)
public final class ATest {
...
您还可以同时运行所有测试类:
import com.mycila.junit.concurrent.ConcurrentSuiteRunner;
@RunWith(ConcurrentSuiteRunner.class)
@Suite.SuiteClasses({ATest.class, ATest2.class, ATest3.class})
public class MySuite {
}
最重要的是:
<代码
<dependency>
<groupId>com.mycila</groupId>
<artifactId>mycila-junit</artifactId>
<version>1.4.ga</version>
</dependency>
@Test
public final void runConcurrentMethod() throws InterruptedException {
ExecutorService exec = Executors.newFixedThreadPool(16);
for (int i = 0; i < 10000; i++) {
exec.execute(new Runnable() {
@Override
public void run() {
concurrentMethod();
}
});
}
exec.shutdown();
exec.awaitTermination(50, TimeUnit.SECONDS);
}
private void concurrentMethod() {
//do and assert something
}