Junit测试多线程时遇到的问题

版权声明:转载请注明出处 https://blog.csdn.net/aimashi620/article/details/81448679

问题的产生
这个问题是我在做支付宝自动对账功能时发现的,因为支付宝对账接口下载的对账单是zip压缩文件形式返回的,所以要实现自动对账功能需要在我调用支付宝对账接口下载完zip文件之前先启动一个线程去监控我用于存放zip文件的文件夹,当这个文件夹有zip文件生成时,自动触发“解压”方法来解压zip文件。方法写好之后我用junit框架去测试,发现一直都没能成功解压zip文件,我通过输出日志发现,是有调到“解压”方法的,但是在“解压”方法执行完成之前程序就已经终止了,后来我用main函数的方式代替了junit来进行测试,发现程序能自动解压,由此得出:junit不支持多线程测试(这种说法不完全正确,因为网上好像有大神实现用junit测试多线程的,具体怎样实现我还没有深入研究,只确定原生的junit是不支持多线程测试的)


由于我自己写的支付宝自动对账功能涉及的代码较多,逻辑相对复杂,不太适合用于讲解这个问题,所以我在网上找了另外一个例子供大家参考:例子来自https://www.cnblogs.com/yanphet/p/5774291.html

/**
 * @Title: TestDoWork.java
 * @Describe:
 * @author: Mr.Yanphet
 * @Email: [email protected]
 * @date: 2016年8月15日 下午5:50:03
 * @version: 1.0
 */
public class TestDoWork {

    class DoWork implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                long milliSecond = System.currentTimeMillis();
                System.out.println("i=" + i + ",milliSecond=" + milliSecond);// 输出循环次数和当前的系统时间
            }
        }

    }

    @Test
    public void test() {
        DoWork dw = new DoWork();
        Thread t = new Thread(dw);
        t.start();
    }

}

输出结果

i=751,milliSecond=1471257586416
i=752,milliSecond=1471257586416
i=753,milliSecond=1471257586416
i=754,milliSecond=1471257586416
i=755,milliSecond=1471257586416
i=756,milliSecond=1471257586416
i=757,milliSecond=1471257586416
i=758,milliSecond=1471257586416

从结果可以看到,循环到了759次后就没再输出了,说明子线程还没结束任务,整个程序就被强迫结束了。
既然知道了现象,那么为什么会出现这样的现象呢,贴出部分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虚拟机,jvm都自身难保了,所以子线程也就对不住你咧…
解决办法:
1 简单粗暴地让主线程休眠一段时间,然后让子线程能够运行结束。但是这个方法的弊端是,你不知道子线程的运行时间,所以需要看脸=_=
  Thread.sleep();
2 使用CountDownLatch工具类,让主线程阻塞,直到子线程运行结束或者阻塞超时,这个方法要比第一个方法好点。
  countDownLatch.await(5, TimeUnit.MINUTES);
至于还有其他方法,笔者看到很多大神自己写的Junit支持多线程,有兴趣的读者自行度娘…

猜你喜欢

转载自blog.csdn.net/aimashi620/article/details/81448679