使用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);
    }
發佈了33 篇原創文章 · 獲贊 5 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章