51Testing软件测试论坛

标题: Junit单元测试多线程的问题 [打印本页]

作者: 司格特    时间: 2018-3-8 14:53
标题: Junit单元测试多线程的问题
今天下午很快完成了一个接口的监控功能,然后屁颠屁颠地用Junit开始单元测试。然后我就开始陷入
崩溃的边缘...

监控结束后需要将监控结果以邮件的形式发送给运营的小伙伴维护,前面测试还是很顺利,到了开多
线程发邮件时就不行了,

程序也不报错,也接收不到邮件。然后改代码再测试,再冥思一会儿,再改再测试,还是无果,最后选
择度娘一下,结论是:

Junit单元测试不支持多线程

然后,整个人都不好了...浪费了我好多时间,就是因为这个!!!

虽然知道了结果,但是笔者还是需要亲自验证一下。
  1. /**
  2. * @Title: TestDoWork.java
  3. * @Describe:
  4. * @author: Mr.Yanphet
  5. * @Email: mr_yanphet@163.com
  6. * @date: 2016年8月15日 下午5:50:03
  7. * @version: 1.0
  8. */
  9. public class TestDoWork {

  10.     class DoWork implements Runnable {

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

  18.     }

  19.     @Test
  20.     public void test() {
  21.         DoWork dw = new DoWork();
  22.         Thread t = new Thread(dw);
  23.         t.start();
  24.     }

  25. }
  26. 复制代码
  27. 输出结果如下(笔者省略了部分输出):

  28. 复制代码
  29. .....
  30. i=751,milliSecond=1471257586416
  31. i=752,milliSecond=1471257586416
  32. i=753,milliSecond=1471257586416
  33. i=754,milliSecond=1471257586416
  34. i=755,milliSecond=1471257586416
  35. i=756,milliSecond=1471257586416
  36. i=757,milliSecond=1471257586416
  37. i=758,milliSecond=1471257586416
  38. 复制代码
复制代码
从结果可以看到,循环到了759次后就没再输出了,说明子线程还没结束任务,整个程序就被强迫结束了。

既然知道了现象,那么为什么会出现这样的现象呢,贴出部分Junit4 TestRunner源码就知道了
  1. public static final int SUCCESS_EXIT = 0;
  2. public static final int FAILURE_EXIT = 1;
  3. public static final int EXCEPTION_EXIT = 2;

  4. public static void main(String args[]) {
  5.     TestRunner aTestRunner = new TestRunner();
  6.     try {
  7.         TestResult r = aTestRunner.start(args);
  8.         if (!r.wasSuccessful())
  9.             System.exit(FAILURE_EXIT);
  10.         System.exit(SUCCESS_EXIT);
  11.     } catch (Exception e) {
  12.         System.err.println(e.getMessage());
  13.         System.exit(EXCEPTION_EXIT);
  14.     }
  15. }
  16. 复制代码
  17. 再贴上TestResult部分源码,以供参考

  18. 复制代码
  19. protected  List<TestFailure>    fFailures
  20. protected  List<TestFailure>    fErrors

  21. public synchronized boolean wasSuccessful() {
  22.     return failureCount() == 0 && errorCount() == 0;
  23. }

  24. public synchronized int errorCount() {
  25.     return fErrors.size();
  26. }

  27. public synchronized int failureCount() {
  28.     return fFailures.size();
  29. }
复制代码
在TestRunner中可以看出,如果是单线程,当测试主线程执行结束后,不管子线程是否结束,都会回
调TestResult的wasSuccessful方法,

然后判断结果是成功还是失败,最后调用相应的System.exit()方法。大家都知道这个方法是用来结束
当前正在运行中的java虚拟机,jvm都自身难保了,所以子线程也就对不住你咧...

解决办法:

1 简单粗暴地让主线程休眠一段时间,然后让子线程能够运行结束。但是这个方法的弊端是,你不知道
子线程的运行时间,所以需要看脸=_=

  Thread.sleep();

2 使用CountDownLatch工具类,让主线程阻塞,直到子线程运行结束或者阻塞超时,这个方法要比第一
个方法好点。

  countDownLatch.await(5, TimeUnit.MINUTES);

至于还有其他方法,笔者看到很多大神自己写的Junit支持多线程,有兴趣的读者自行度娘...


作者: jingzizx    时间: 2018-3-8 16:06

学习




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