簡體   English   中英

一個TestNg多線程問題。 TestNg不尊重子線程

[英]A TestNg Multithreading Issue. TestNg does not respect the child threads

我有一個非常簡單的類,它將列表異步寫入文件:

import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;

public enum FileOps {
    INSTANCE;

    private ExecutorService threadPool = Executors.newFixedThreadPool(30);
    private AtomicInteger fileCount = new AtomicInteger(0);

    private <T> void writeListToFile(String fileName, List<T> obj) {
        FileWriter writer = null;
        Type tType = new TypeToken<ArrayList<T>>() {
            private static final long serialVersionUID = 4376511240656742709L;
        }.getType();
        Gson gson = new Gson();
        try {
            writer = new FileWriter(fileName);
            writer.append(gson.toJson(obj, tType));
            writer.flush();
        } catch (Exception e) {

        } finally {
            try {
                writer.close();
            } catch (IOException e) {
            }
        }
    }

    public <T> void asynWriteListToFile(List<T> obj){
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                String fileName = "C:\\data\\" + fileCount.incrementAndGet() + "_data.txt";
                System.out.println(fileName);
                FileOps.INSTANCE.writeListToFile(fileName, obj);
            }
        });
    }

}

我已經使用TestNg為此類編寫了單元測試

import java.util.ArrayList;
import java.util.List;

import org.testng.annotations.Test;

public class FileOpsTest {

    @Test
    public void asynWriteListToFile() {
        List<Integer> list = new ArrayList<>();
        list.add(3);
        for (int i = 0; i < 10000; i++) {
            FileOps.INSTANCE.asynWriteListToFile(list);
        }

    }
}

我有一個奇怪的情況。 在我的TestNg執行中,測試引擎如何不等待子線程完成。 因此,我期望在磁盤上寫入10000個文件,但是每次看到較少的文件寫入磁盤時。 但是,如果我使用main方法編寫客戶端,則一切正常。

import java.util.ArrayList;
import java.util.List;

public class FileOpsClient {

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(3);
        for (int i = 0; i < 10000; i++) {
            FileOps.INSTANCE.asynWriteListToFile(list);
        }
    }
}

testNg引擎以某種方式關閉了我的線程池。

由於文件是異步寫入的,因此FileOpsTest.asynWriteListToFile()在文件全部寫入之前結束,並且org.testng.TestNG(或您的IDE的測試運行器)調用System.exit(int) (例如TestNG.java:1375 )。

相反, FileOpsClient.main(String[])不會顯式調用System.exit(int) ,因此JVM等待線程結束,因為它們不是守護程序線程。 有關更多詳細信息,請參見如何使TestNG等待測試完成然后再關閉它

在這種情況下,您可以進行一些更改,以便您的測試可以有效地調用threadPool.awaitTermination(long, TimeUnit) (例如,將FileOps.threadPool “本地包”,而不是“ private”,然后從測試中訪問它,添加一個FileOps上的方法來做到這一點,並保持FileOps.threadPool “私有”等)。

但是,如果您的目標是進行單元測試,那么我建議ExecutorService是一個“尷尬的協作者”,並且您應該重構代碼,以便1)您可以使用模擬的ExecutorService測試生成線程(請參閱如何對該ExecutorService進行單元測試)生成新的任務線程? ),2)您可以測試列表到文件邏輯的實際寫入,而與如何將其作為異步任務創建無關,並且3)不要直接使用FileWriter而是直接使用Writer以便在測試時還可以進行模擬,並避免在單元測試中實際寫入/讀取文件,並在需要時將此類練習留給集成測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM