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

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>    fFailures
protected  List<TestFailure>    fErrors

public 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);
    }
posted @ 2017-03-16 10:55  ~hello ~world  阅读(1049)  评论(0编辑  收藏  举报