[英]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.