您的位置:軟件測(cè)試 > 開源軟件測(cè)試 > 開源單元測(cè)試工具 > junit
Junit單元測(cè)試多線程的問題
作者:Mr.Yanphet 發(fā)布時(shí)間:[ 2016/8/18 11:24:34 ] 推薦標(biāo)簽:多線程 Junit 單元測(cè)試

  下午很快完成了一個(gè)接口的監(jiān)控功能,然后屁顛屁顛地用Junit開始單元測(cè)試。然后我開始陷入崩潰的邊緣...
  監(jiān)控結(jié)束后需要將監(jiān)控結(jié)果以郵件的形式發(fā)送給運(yùn)營(yíng)的小伙伴維護(hù),前面測(cè)試還是很順利,到了開多線程發(fā)郵件時(shí)不行了,
  程序也不報(bào)錯(cuò),也接收不到郵件。然后改代碼再測(cè)試,再冥思一會(huì)兒,再改再測(cè)試,還是無果,后選擇度娘一下,結(jié)論是:
  Junit單元測(cè)試不支持多線程
  然后,整個(gè)人都不好了...浪費(fèi)了我好多時(shí)間,是因?yàn)檫@個(gè)!!!
  雖然知道了結(jié)果,但是筆者還是需要親自驗(yàn)證一下。
/**
* @Title: TestDoWork.java
* @Describe:
* @author: Mr.Yanphet
* @Email: mr_yanphet@163.com
* @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);// 輸出循環(huán)次數(shù)和當(dāng)前的系統(tǒng)時(shí)間
}
}
}
@Test
public void test() {
DoWork dw = new DoWork();
Thread t = new Thread(dw);
t.start();
}
}
  輸出結(jié)果如下(筆者省略了部分輸出):
  .....
  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
  從結(jié)果可以看到,循環(huán)到了759次后沒再輸出了,說明子線程還沒結(jié)束任務(wù),整個(gè)程序被強(qiáng)迫結(jié)束了。
  既然知道了現(xiàn)象,那么為什么會(huì)出現(xiàn)這樣的現(xiàn)象呢,貼出部分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中可以看出,如果是單線程,當(dāng)測(cè)試主線程執(zhí)行結(jié)束后,不管子線程是否結(jié)束,都會(huì)回調(diào)TestResult的wasSuccessful方法,
  然后判斷結(jié)果是成功還是失敗,后調(diào)用相應(yīng)的System.exit()方法。大家都知道這個(gè)方法是用來結(jié)束當(dāng)前正在運(yùn)行中的java虛擬機(jī),jvm都
  自身難保了,所以子線程也對(duì)不住你咧...
  解決辦法:
  1 簡(jiǎn)單粗暴地讓主線程休眠一段時(shí)間,然后讓子線程能夠運(yùn)行結(jié)束。但是這個(gè)方法的弊端是,你不知道子線程的運(yùn)行時(shí)間,所以需要看臉=_=
  Thread.sleep();
  2 使用CountDownLatch工具類,讓主線程阻塞,直到子線程運(yùn)行結(jié)束或者阻塞超時(shí),這個(gè)方法要比第一個(gè)方法好點(diǎn)。
  countDownLatch.await(5, TimeUnit.MINUTES);
  至于還有其他方法,筆者看到很多大神自己寫的Junit支持多線程,有興趣的讀者自行度娘...

軟件測(cè)試工具 | 聯(lián)系我們 | 投訴建議 | 誠(chéng)聘英才 | 申請(qǐng)使用列表 | 網(wǎng)站地圖
滬ICP備07036474 2003-2017 版權(quán)所有 上海澤眾軟件科技有限公司 Shanghai ZeZhong Software Co.,Ltd