使用Junit进行耗时多线程测试

来源:互联网 发布:jquery 转 js 编辑:程序博客网 时间:2024/06/07 14:56

1、引言

有个需求要求将对一个接口进行并发测试,查看是否符合需求,由于习惯使用Junit进行测试,所以就写了以下操作

  @Test    public void testsend(){        final  AtomicLong l = new AtomicLong(0);        long begin = System.currentTimeMillis();        ExecutorService pool = Executors.newFixedThreadPool(100);        for (int j = 0;j<100;j++ ){            Runnable t = new Runnable() {                public void run() {                    for(int i = 0; i < 10000;i++){                        MQProductHelper.send("ABILITY_BILL", "hello");                        System.out.println(l.incrementAndGet());                    }                }            };            pool.execute(t);        }        long end = System.currentTimeMillis();        System.out.println(end - begin);    }

然后发现主线程立即执行完毕,然后其他线程的耗时操作还没执行一会就全部终止了,一开始一脸懵逼的看着还以为是自己代码写错了不能并发操作,但是发现每次子线程还是有执行一会,只是任务没结束线程就被杀掉了,接下来尝试在main方法中进行测试,然后发现接口又可以正常测试,那么是不是Junit不支持进行多线程单元测试呢,查找了下原因

2、原因

查看Junit4 TestRunner源码发现以下内容

public static final int SUCCESS_EXIT = 0;public static final int FAILURE_EXIT = 1;public static final int EXCEPTION_EXIT = 2;public static void main(String args[]) {    TestRunner aTestRunner = new TestRunner();    try {        TestResult r = aTestRunner.start(args);        if (!r.wasSuccessful())            System.exit(FAILURE_EXIT);        System.exit(SUCCESS_EXIT);    } catch (Exception e) {        System.err.println(e.getMessage());        System.exit(EXCEPTION_EXIT);    } }

再贴上TestResult部分源码,以供参考

protected  List<TestFailure>    fFailuresprotected  List<TestFailure>    fErrorspublic synchronized boolean wasSuccessful() {    return failureCount() == 0 && errorCount() == 0;}public synchronized int errorCount() {    return fErrors.size();}public synchronized int failureCount() {    return fFailures.size();}

在TestRunner中可以看出,当测试主线程执行结束后,不管子线程是否结束,都会回调TestResult的wasSuccessful方法,然后判断结果是成功还是失败,最后调用相应的System.exit()方法,这个方法是用来结束当前正在运行中的java虚拟机,所以子线程就全部GG了

3、解决方案

1、 主线程休眠

这个方案比较粗暴,而且无法计算运行时间,完全靠自己推测大概需要多长时间运行完子线程,然后让主线程休眠一段时间

public void testsend(){        final  AtomicLong l = new AtomicLong(0);        long begin = System.currentTimeMillis();        ExecutorService pool = Executors.newFixedThreadPool(100);        for (int j = 0;j<100;j++ ){            Runnable t = new Runnable() {                public void run() {                    for(int i = 0; i < 10000;i++){                        MQProductHelper.send("ABILITY_BILL", "hello");                        System.out.println(l.incrementAndGet());                    }                }            };            pool.execute(t);        }        long end = System.currentTimeMillis();        try {            Thread.sleep(120000);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println(end - begin);    }

2.使用CountDownLatch工具类,让主线程阻塞,直到子线程运行结束或者阻塞超时

  @Test    public void testsend(){        CountDownLatch latch=new CountDownLatch(100);        final  AtomicLong l = new AtomicLong(0);        long begin = System.currentTimeMillis();        ExecutorService pool = Executors.newFixedThreadPool(100);        for (int j = 0;j<100;j++ ){            Runnable t = new Runnable() {                public void run() {                    for(int i = 0; i < 10000;i++){                        MQProductHelper.send("ABILITY_BILL", "hello");                        System.out.println(l.incrementAndGet());                    }                }            };            pool.execute(t);        }        long end = System.currentTimeMillis();        try {            latch.await();        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println(end - begin);    }
0 0