51Testing软件测试论坛

标题: JUnit4 多线程执行测试用例 (下) [打印本页]

作者: 八戒你干嘛    时间: 2017-8-8 11:15
标题: JUnit4 多线程执行测试用例 (下)
本帖最后由 八戒你干嘛 于 2017-8-8 11:19 编辑

由于字数限制,此贴分为两贴,此贴为下贴。


上贴地址⬇️
JUnit4 多线程执行测试用例 (上)






只要在单个测试类前,加上注解:@RunWith(MultiThreadRunner.class),就可以并发的执行用例。
如下图:


(三)自定义聚合多个类进行多线程执行的Runner有时我们需要聚合同一个模块的测试类,如果使用@RunWith(Suite.class)@SuiteClasses({A.class,B.class}),当类较多时,需要一一列举,效率不高;可以使用ClasspathSuite,支持过滤,将类名符合一定规则的类聚合,官方文档
实现代码如下:
  1. package com.weibo.concurrent;

  2. import org.junit.experimental.categories.Categories;
  3. import org.junit.extensions.cpsuite.ClasspathSuite;
  4. import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
  5. import org.junit.runner.Runner;
  6. import org.junit.runners.ParentRunner;
  7. import org.junit.runners.model.InitializationError;
  8. import org.junit.runners.model.RunnerBuilder;
  9. import org.junit.runners.model.RunnerScheduler;

  10. import com.weibo.common.MbLogger;

  11. import java.lang.reflect.Method;
  12. import java.util.ArrayList;
  13. import java.util.Arrays;
  14. import java.util.LinkedList;
  15. import java.util.List;
  16. import java.util.Queue;
  17. import java.util.concurrent.CompletionService;
  18. import java.util.concurrent.ExecutorCompletionService;
  19. import java.util.concurrent.ExecutorService;
  20. import java.util.concurrent.Executors;
  21. import java.util.concurrent.Future;
  22. import java.util.concurrent.ThreadFactory;
  23. import java.util.concurrent.TimeUnit;
  24. import java.util.concurrent.atomic.AtomicInteger;

  25. /**
  26. * @author hugang
  27. *
  28. **/
  29. public final class ConcurrentSuite extends ClasspathSuite {

  30.     public static Runner MulThread(Runner runner) {
  31.         if (runner instanceof ParentRunner) {
  32.             // setScheduler(RunnerScheduler scheduler):Sets a scheduler that
  33.             // determines the order and parallelization of children
  34.             // RunnerScheduler:Represents a strategy for scheduling when
  35.             // individual test methods should be run (in serial or parallel)
  36.             ((ParentRunner) runner).setScheduler(new RunnerScheduler() {
  37.                 private final ExecutorService fService = Executors
  38.                         .newCachedThreadPool();

  39.                 // private final ExecutorService fService =
  40.                 // Executors.newFixedThreadPool(10);

  41.                 // Schedule a child statement to run
  42.                 public void schedule(Runnable childStatement) {
  43.                     this.fService.submit(childStatement);
  44.                 }

  45.                 // Override to implement any behavior that must occur after all
  46.                 // children have been scheduled
  47.                 public void finished() {
  48.                     try {
  49.                         this.fService.shutdown();
  50.                         this.fService.awaitTermination(9223372036854775807L,
  51.                                 TimeUnit.NANOSECONDS);
  52.                     } catch (InterruptedException e) {
  53.                         e.printStackTrace(System.err);
  54.                     }
  55.                 }
  56.             });
  57.         }
  58.         return runner;
  59.     }

  60.     public ConcurrentSuite(final Class<?> klass) throws InitializationError {
  61.         // 调用父类ClasspathSuite构造函数
  62.         // AllDefaultPossibilitiesBuilder根据不同的测试类定义(@RunWith的信息)返回Runner,使用职责链模式
  63.         super(klass, new AllDefaultPossibilitiesBuilder(true) {
  64.             @Override
  65.             public Runner runnerForClass(Class<?> testClass) throws Throwable {
  66.                 List<RunnerBuilder> builders = Arrays
  67.                         .asList(new RunnerBuilder[] { ignoredBuilder(),
  68.                                 annotatedBuilder(), suiteMethodBuilder(),
  69.                                 junit3Builder(), junit4Builder() });
  70.                 for (RunnerBuilder each : builders) {
  71.                     // 根据不同的测试类定义(@RunWith的信息)返回Runner
  72.                     Runner runner = each.safeRunnerForClass(testClass);
  73.                     if (runner != null)
  74.                         // 方法级别,多线程执行
  75.                         return MulThread(runner);
  76.                 }
  77.                 return null;
  78.             }
  79.         });

  80.         // 类级别,多线程执行
  81.         setScheduler(new RunnerScheduler() {
  82.             private final ExecutorService fService = Executors
  83.                     .newCachedThreadPool();

  84.             @Override
  85.             public void schedule(Runnable paramRunnable) {
  86.                 // TODO Auto-generated method stub
  87.                 fService.submit(paramRunnable);
  88.             }

  89.             @Override
  90.             public void finished() {
  91.                 // TODO Auto-generated method stub
  92.                 try {
  93.                     fService.shutdown();
  94.                     fService.awaitTermination(Long.MAX_VALUE,
  95.                             TimeUnit.NANOSECONDS);
  96.                 } catch (InterruptedException e) {
  97.                     e.printStackTrace(System.err);
  98.                 }
  99.             }

  100.         });
  101.     }

  102. }
复制代码

新建一个聚合的IntegrationBeijingOneTests.java文件:
  1. @RunWith(ConcurrentSuite.class)
  2. @ClassnameFilters({"com.weibo.cases.xuelian.*Test", "!.*RemindTest","com.weibo.cases.maincase.*Xuelian"})
  3. @Concurrent
  4. public interface IntegrationBeijingOneTests {

  5. }
复制代码

再建一个suite文件,XuelianTestSuite.java:
  1. package com.weibo.cases.suite;
  2. import org.junit.experimental.categories.Categories;
  3. import org.junit.runner.RunWith;
  4. import org.junit.runners.Suite.SuiteClasses;

  5. @RunWith(Categories.class)
  6. @SuiteClasses( IntegrationBeijingOneTests.class )
  7. public class XuelianTestSuite {

  8. }
复制代码

直接运行XuelianTestSuite.java即可,执行过程如下:


写在最后:设计测试用例时需考虑线程安全。
建议(本组内用例):
1.账号的使用,同一个测试类中每个测试方法之间需使用不同测试账号(之前未考虑并发,串行执行时方法间使用同样账号,没有影响),咱们组V4的用例共1516个,假设每个用例使用3个账号,则同时执行用例时,则需4548个账号,现库里有1617个账号,可能需要增加用户(空间换时间); 当然也可以控制并发执行测试方法的数量,来减少用户的使用,比如可以指定同时5个(可调)测试方法并发执行,当然,执行时间上就会相应的增加。
2.非final的全局变量,全改写到测试方法内定义,变成局部变量。


作者: icerman    时间: 2017-8-25 09:09
@Concurrent,我这为什么不识别




欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2