51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 3439|回复: 1
打印 上一主题 下一主题

[转贴] JUnit4 多线程执行测试用例 (上)

[复制链接]
  • TA的每日心情
    无聊
    2024-9-19 09:07
  • 签到天数: 11 天

    连续签到: 2 天

    [LV.3]测试连长

    跳转到指定楼层
    1#
    发表于 2017-8-8 11:14:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    本帖最后由 八戒你干嘛 于 2017-8-8 11:18 编辑

    前言:
    之前发过类似的文章,现重新调整了部分格式,部分内容稍作调整和添加,便于阅读。
    评论中,有人说直接使用TestNG,就可以实现多线程,是的,但是方式不一样;我们是按照自己的需求对JUnit4自定义多线程Runner,直接在某个类加上相应的注解即可,运行该类就行,支持类和方法级别;TestNG只在方法上有注解 @Test(threadPoolSize = m, invocationCount = n, timeOut = i)实现了对这个方法进行多线程重复跑,threadPoolSize多少个线程执行该方法,invocationCount被执行次数,timeOut每次执行该方法的超时时间,这仅是用多线程重复执行这一个方法,而不是类下面的所有方法同时并发执行,并不是所谓的方法级别并发;TestNG是在xml指定并发的类,方法,组件,具体参照TestNG Executing Parallel Tests Example
    这里不讨论TestNG与JUnit4谁好谁坏,JUnit 4 vs TestNG,只要能满足自己的业务需要即可。
    本文仅针对JUnit4进行二次开发。
    JUnit4本身是支持多线程,但没有提供多线程的注解;本文将介绍JUnit4自身的多线程实现,自定义对单个类进行多线程执行的Runner和自定义聚合多个类进行多线程执行的Runner。
    (一)JUnit4自身的多线程实现JUnit4提供了ParallerComputer类来使用多线程执行测试用例。
    java.lang.Object
      extended by org.junit.runner.Computer
          extended by org.junit.experimental.ParallelComputer
    源码如下:
    1. 001    package org.junit.experimental;
    2. 002   
    3. 003    import java.util.concurrent.ExecutorService;
    4. 004    import java.util.concurrent.Executors;
    5. 005    import java.util.concurrent.TimeUnit;
    6. 006   
    7. 007    import org.junit.runner.Computer;
    8. 008    import org.junit.runner.Runner;
    9. 009    import org.junit.runners.ParentRunner;
    10. 010    import org.junit.runners.model.InitializationError;
    11. 011    import org.junit.runners.model.RunnerBuilder;
    12. 012    import org.junit.runners.model.RunnerScheduler;
    13. 013   
    14. 014    public class ParallelComputer extends Computer {
    15. 015        private final boolean classes;
    16. 016   
    17. 017        private final boolean methods;
    18. 018   
    19. 019        public ParallelComputer(boolean classes, boolean methods) {
    20. 020            this.classes = classes;
    21. 021            this.methods = methods;
    22. 022        }
    23. 023   
    24. 024        public static Computer classes() {
    25. 025            return new ParallelComputer(true, false);
    26. 026        }
    27. 027   
    28. 028        public static Computer methods() {
    29. 029            return new ParallelComputer(false, true);
    30. 030        }
    31. 031   
    32. 032        private static Runner parallelize(Runner runner) {
    33. 033            if (runner instanceof ParentRunner) {
    34. 034                ((ParentRunner<?>) runner).setScheduler(new RunnerScheduler() {
    35. 035                    private final ExecutorService fService = Executors.newCachedThreadPool();
    36. 036   
    37. 037                    public void schedule(Runnable childStatement) {
    38. 038                        fService.submit(childStatement);
    39. 039                    }
    40. 040   
    41. 041                    public void finished() {
    42. 042                        try {
    43. 043                            fService.shutdown();
    44. 044                            fService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
    45. 045                        } catch (InterruptedException e) {
    46. 046                            e.printStackTrace(System.err);
    47. 047                        }
    48. 048                    }
    49. 049                });
    50. 050            }
    51. 051            return runner;
    52. 052        }
    53. 053        //  类的维度
    54. 054        @Override
    55. 055        public Runner getSuite(RunnerBuilder builder, java.lang.Class<?>[] classes)
    56. 056                throws InitializationError {
    57. 057            Runner suite = super.getSuite(builder, classes);
    58. 058            return this.classes ? parallelize(suite) : suite;
    59. 059        }
    60. 060        // 方法的维度
    61. 061        @Override
    62. 062        protected Runner getRunner(RunnerBuilder builder, Class<?> testClass)
    63. 063                throws Throwable {
    64. 064            Runner runner = super.getRunner(builder, testClass);
    65. 065            return methods ? parallelize(runner) : runner;
    66. 066        }
    67. 067    }
    复制代码
    ParallelComputer类中parallelize(Runner runner)方法重写了
    ParentRunner类的方法runner.setScheduler(RunnerSchedulerscheduler) ,重新定义了调度顺序,定义了一个线程池 private final ExecutorService fService = Executors.newCachedThreadPool()来多线程执行,运行结束后finished(),关闭线程池fService.shutdown(),并返回该runner。
    其中ParallelComputer类重写了父类 Computer的getSuite()和getRunner:
    1. @Override
    2. public Runner getSuite(RunnerBuilder builder, java.lang.Class<?>[] classes)
    3.         throws InitializationError {
    4.     Runner suite = super.getSuite(builder, classes);
    5.     return this.classes ? parallelize(suite) : suite;
    6. }

    7. @Override
    8. protected Runner getRunner(RunnerBuilder builder, Class<?> testClass)
    9.        throws Throwable {
    10.    Runner runner = super.getRunner(builder, testClass);
    11.     return methods ? parallelize(runner) : runner;
    12. }
    复制代码
    getSuite()和getRunner()根据ParallelComputer类的全局final变量classes和methods的值去决定是否多线程执行;
    classes为true时,并发以类为维度,如下:
    1. return this.classes ? parallelize(suite) : suite;
    复制代码
    methods为true时,并发以方法为维度,如下:
    1. return methods ? parallelize(runner) : runner;
    复制代码
    ParallelComputer类提供了带参的构造函数:
    1. public ParallelComputer(boolean classes, boolean methods)
    复制代码
    可以在类初始化时,直接定义多线程执行(不同维度)的对象。
    JUnitCore类中的方法runClasses():
    1. public static Result runClasses(Computer computer,Class<?>... classes)
    复制代码
    可以在main()函数里直接运行测试用例,参数Computer是ParallelComputer的父类,可以直接new ParallelComputer(boolean classes, boolean methods)对象作为第一个形参。

    实例1:
    1. public class A {

    2.     @Test
    3.     public void a() {
    4.         assertThat(3, is(1));
    5.     }

    6.     @Test
    7.     public void b() {
    8.         assertThat(3, not(1));
    9.     }

    10. }

    11. public class B {

    12.     @Test
    13.     public void c() {
    14.         assertThat(3, greaterThan(1));
    15.     }

    16.     @Test
    17.     public void d() {
    18.         assertThat(3, lessThan(1));
    19.     }

    20. }

    复制代码
    1. public class ParallelTest {

    2.     public static void main(String[] args) {
    3.         Class[] cls = { A.class, B.class };

    4.         Result rt;

    5.         // 并发以类为维度
    6.         // rt = JUnitCore.runClasses(ParallelComputer.classes(), cls);

    7.         // 并发以方法为维度
    8.         // rt = JUnitCore.runClasses(ParallelComputer.methods(), cls);

    9.         // 并发以类和方法为维度
    10.         rt = JUnitCore.runClasses(new ParallelComputer(true, true), cls);

    11.         System.out.println(rt.getRunCount() + " " + rt.getFailures()  + " " + rt.getRunTime());
    12.     }

    13. }
    复制代码
    // A,B两个类并发执行,但类的方法还是串行执行;
    JUnitCore.runClasses(ParallelComputer.classes(), cls);
    // A,B两个类串行执行,但类的方法并发执行
    JUnitCore.runClasses(ParallelComputer.methods(), cls);
    // A,B两个类并发执行,其方法也并发执行
    JUnitCore.runClasses(new ParallelComputer(true, true), cls);
    (二)自定义对单个类进行多线程执行的Runner
    1. package com.weibo.concurrent;

    2. import java.util.concurrent.atomic.AtomicInteger;

    3. import org.junit.runner.notification.RunNotifier;
    4. import org.junit.runners.BlockJUnit4ClassRunner;
    5. import org.junit.runners.model.FrameworkMethod;
    6. import org.junit.runners.model.InitializationError;
    7. import org.junit.runners.model.Statement;

    8. /**
    9. * Runs all tests in parallel and waits for them to complete.
    10. *
    11. */
    12. public class MultiThreadedRunner extends BlockJUnit4ClassRunner {

    13.     private AtomicInteger numThreads;

    14.     public static int maxThreads = 10;

    15.     public MultiThreadedRunner (Class<?> klass) throws InitializationError {
    16.         super (klass);
    17.         numThreads = new AtomicInteger(0);
    18.     }

    19.     // Runs the test corresponding to child,which can be assumed to be an element of the list returned by getChildren()
    20.     @Override
    21.     protected void runChild(final FrameworkMethod method, final RunNotifier notifier) {
    22.         while (numThreads.get() > maxThreads) {
    23.             try {
    24.                 Thread.sleep(1000);
    25.             } catch (InterruptedException e) {
    26.                 System.err.println ("Interrupted: " + method.getName());
    27.                 e.printStackTrace();
    28.                 return; // The user may have interrupted us; this won't happen normally
    29.             }
    30.         }
    31.         numThreads.incrementAndGet();
    32.         // 用线程执行父类runChild(method, notifier)
    33.         new Thread (new Test(method, notifier)).start();
    34.     }

    35.     // childrenInvoker() call runChild(Object, RunNotifier) on each object returned by getChildren()
    36.     // evaluate() run the action, 调用父类BlockJUnit4ClassRunner的evaluate()
    37.     @Override
    38.     protected Statement childrenInvoker(final RunNotifier notifier) {
    39.         return new Statement() {
    40.             @Override
    41.             public void evaluate() throws Throwable {
    42.                 MultiThreadedRunner.super.childrenInvoker(notifier).evaluate();
    43.                 // wait for all child threads (tests) to complete
    44.                 while (numThreads.get() > 0) {
    45.                     Thread.sleep(1000);
    46.                 }
    47.             }
    48.         };
    49.     }

    50.     class Test implements Runnable {
    51.         private final FrameworkMethod method;
    52.         private final RunNotifier notifier;

    53.         public Test (final FrameworkMethod method, final RunNotifier notifier) {
    54.             this.method = method;
    55.             this.notifier = notifier;
    56.         }

    57.         @Override
    58.         public void run () {
    59.             System.err.println (method.getName());
    60.             MultiThreadedRunner.super.runChild(method, notifier);
    61.             numThreads.decrementAndGet();
    62.         }
    63.     }

    64. }

    复制代码

    由于字数限制:请转至
    JUnit4 多线程执行测试用例 (下)

    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    该用户从未签到

    2#
    发表于 2017-8-8 13:33:32 | 只看该作者
    可以用testng来实现并发测试,加一个注解就OK了
    回复 支持 反对

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-24 04:00 , Processed in 0.066297 second(s), 22 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表