代码之家  ›  专栏  ›  技术社区  ›  janetsmith

如何运行并发单元测试?

  •  42
  • janetsmith  · 技术社区  · 15 年前

    如何使用junit运行并发测试?

    假设我有课

    public class MessageBoard
    {
        public synchronized void postMessage(String message)
        {
            ....
        }
    
        public void updateMessage(Long id, String message)
        {
            ....
        }
    }
    

    我要同时测试对此邮件的多个访问。 有什么建议吗?我希望对所有setter函数(或任何涉及创建/更新/删除操作的方法)运行这种并发测试。

    12 回复  |  直到 13 年前
        1
  •  22
  •   Brian Agnew    15 年前

    不幸的是我不相信你能 明确地 使用运行时测试来证明代码是线程安全的。您可以针对它抛出任意多个线程,并且它可能/可能不会通过,具体取决于调度。

    也许您应该看看一些静态分析工具,例如 PMD ,它可以确定如何使用同步,并确定使用问题。

        2
  •  16
  •   Peter    15 年前

    我建议使用 MultithreadedTC Bill Pugh (和 Nat Ayewah overview :

    测试并发应用程序。它 具有一个节拍器,用于 多线程中的活动。

    此框架允许您在单独的测试中确定地测试每个线程交错

        3
  •  9
  •   dfa    15 年前

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

    但是,您可以编写一个专门的测试运行程序,生成多个并发线程,然后调用@test注释的方法。

        4
  •  7
  •   Judah Gabriel Himango    15 年前

    TypeMock Racer Microsoft CHESS

    我想Java世界也有类似的东西。

        5
  •  5
  •   stivlo    13 年前

    并发运行可能会导致意外的结果。例如,我刚刚发现,虽然我的测试套件有200个测试在一个接一个地执行时通过了,但是并发执行失败了,我发现这不是线程安全问题,而是一个依赖于另一个的测试,这是一件坏事,我可以解决这个问题。

    Mycila work on JUnit ConcurrentJunitRunner and ConcurrentSuite

    对测试类进行如下注释将导致并发执行测试方法,并发级别为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 是:

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

        6
  •  2
  •   Chris Knight    15 年前

    试试看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次。如果您希望在并行测试中有变化,只需创建一个不同的类。

        7
  •  1
  •   Justin    15 年前

    同步的

    您需要在不同的vm中同时运行测试程序的多个副本。你可以用

    如果你不能让你的测试框架来做,你可以自己启动一些虚拟机。 流程构建器的工作是一个痛苦的路径和什么都没有,但这里是总的草图:

    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**
    
        8
  •  1
  •   Imagist    15 年前

    测试并发性错误是不可能的;您不仅需要验证输入/输出对,而且还必须在测试期间可能发生或可能不发生的情况下验证状态。不幸的是,JUnit没有能力这样做。

        9
  •  1
  •   Toby Daniel C. Sobral    9 年前

    您可以使用tempus fugit库并行运行测试方法,并多次模拟负载测试类型环境。尽管前面的一条评论指出post方法是同步的,因此受到保护,但是关联的成员或方法可能涉及到它们本身不受保护的内容,因此 可能的 负荷/浸泡式试验 抓住这些。我建议您设置一个相当粗粒度/端到端类似的测试,以便为您提供捕获任何环路漏洞的最佳机会。

    documentation .

    顺便说一下,我是上述项目的开发人员:)

        10
  •  0
  •   AutomatedTester    15 年前

    TestNG 支持Java中的并发测试。这个 article

    但不确定是否可以同时运行相同的测试

        11
  •  0
  •   Ed Sykes    15 年前

    这里最好的方法是使用系统测试来用请求爆破代码,看看它是否崩溃。然后使用单元测试检查逻辑正确性。我的方法是为异步调用创建一个代理,并让它在测试中同步进行。

        12
  •  0
  •   Lauri Lehmijoki    11 年前

    你也可以试试 HavaRunner