如何运行并发单元测试?(How to run concurrency unit test?)

2019-06-27 19:10发布

如何使用JUnit进行并发性测试?

比方说,我有一个类

public class MessageBoard
{
    public synchronized void postMessage(String message)
    {
        ....
    }

    public void updateMessage(Long id, String message)
    {
        ....
    }
}

我婉同时测试此postMessage的多址接入。 在这个有什么建议? 我想运行这种对我所有的setter函数的并发测试(或涉及创建/更新/删除操作的任何方法)的。

Answer 1:

不幸的是,我不相信你可以明确地证明你的代码是线程安全的使用运行时测试。 只要你喜欢反对它甚至可以把尽可能多的线程,它可以/取决于调度可能无法通过。

也许你应该看一些静态分析工具,如PMD ,可以确定您如何使用同步和标识的使用问题。



Answer 2:

我会建议使用MultithreadedTC -写的并发大师亲自比尔·皮尤 (和纳特艾瓦赫 )。 从他们的报价概述 :

MultithreadedTC是测试并发应用程序的框架。 其特点是,用于提供对在多个线程活动的顺序的精细控制的节拍器。

该框架允许你确定性测试每个线程在单独的测试交织



Answer 3:

你只能证明并发错误的存在,而不是他们的缺席

但是你可以写一个专门的测试运行器会派生多个并发线程,然后调用你的@Test注解的方法。



Answer 4:

在.NET中,有喜欢的工具TypeMock赛车或微软CHESS了为单元测试并发性而设计的。 这些工具不仅可以找到多线程蝽象死锁,但也给你一套重现错误线交错的。

我想像有一个为Java世界中类似的东西。



Answer 5:

同时运行可能会导致意想不到的结果。 举例来说,我才发现,虽然我的测试套件200个测试通过时,由一个执行的一个,它不能并发执行,我挖的是,它不是一个线程安全的问题,而是一个测试依赖于另外一个,这是一件坏事,我可以解决这个问题。

JUnit的ConcurrentJunitRunner和ConcurrentSuite Mycila工作是很有趣的。 相比最新的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 {
}

该Maven的依赖关系是:

<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
}

正如其他人所指出的,是事实,你永远无法确定并发错误是否会出现与否,而是与成千上万十个,或者,一并发执行数千百说16,统计就在你身边。



Answer 6:

试着看一下ActiveTestSuite其中附带的JUnit。 它可以同时启动多个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倍。 如果您在paralell测试要变化,只需要创建一个不同的类。



Answer 7:

在您的示例的postMessage()方法是同步的 ,所以你不会真正看到从一个单一的虚拟机中的任何并发影响,但你也许可以评估的同步版本的性能。

您将需要在不同虚拟机同时运行测试程序的多个副本。 您可以使用

如果你不能让你的测试框架,这样做就可以发动一些虚拟机你的自我。 该进程生成的东西是路径和诸如此类的东西很烦,但这里是一般的草图:

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();
}

我通常不喜欢这样简单的线程测试,像其他人发布,测试是不是正确的证明,但它通常动摇了愚蠢的错误实践中。 它有助于在各种不同条件下测试了很长时间 - 有时并发错误需要一段时间才能体现在测试。

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**


Answer 8:

测试并发错误是不可能的; 你不只是要验证输入/输出对的,但你有可能会或可能不会在您的测试中发生的情况,以验证状态。 不幸的是JUnit是不具备这样做。



Answer 9:

您可以使用的Tempus-福吉特库并行运行,并多次测试方法来模拟负载测试类型的环境。 虽然之前的评论指出,POST方法syncrhonised等保护,相关成员或方法可以涉及其自身得不到保护,所以它可能是一个负载/浸泡型式试验抓住这些。 我建议你设置一个相当粗粒/终端到终端的测试一样给你捕捉任何环洞的最好机会。

请参阅的JUnit的集成部分文档 。

顺便说一句,我一开发商在上述项目:)



Answer 10:

TestNG的具有对Java并发测试支持。 该文章中描述了如何可以使用,并且没有对TestNG的网站文档。

不知道你是否可以在同一时间做同样的测试运行,虽然



Answer 11:

这里最好的方法是使用系统测试与请求爆你的代码,看看它是否倒下。 然后使用单元测试,以检查逻辑正确性。 我将接近这一问题的方法是创建用于异步调用的代理,并把它在测试同步建立。

但是,如果你想在其他的水平,而不是做一个完整的安装和完整的环境,你可以通过一个单独的线程创建的对象做到这一点在JUnit中,然后创建大量线程的那团火请求你的对象,并阻塞主线程直到它完成。 这种方法可以使测试失败间歇如果你没有得到它的权利。



Answer 12:

您也可以尝试HavaRunner 。 它默认运行在平行试验。



文章来源: How to run concurrency unit test?