java - TestNg 多线程问题。 TestNg 不尊重子线程

标签 java multithreading testng

我有一个非常简单的类,它将列表异步写入文件:

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 会等待线程结束,因为它们不是守护线程。请参阅How to make TestNG wait for my test to complete before shutting it down了解更多详情。

在您的情况下,您可以进行一些更改,以便您的测试可以有效地调用 threadPool.awaitTermination(long, TimeUnit) (例如,使 FileOps.threadPool "package local”而不是“private”,并从测试中访问它,在 FileOps 上添加一个方法来为您执行此操作,并保持 FileOps.threadPool “private”等。 )。

但是,如果您的目标是进行单元测试,那么我建议 ExecutorService 是一个“尴尬的协作者”,并且您应该重构您的代码,以便 1)您可以使用模拟 ExecutorService (请参阅 How to unit test that ExecutorService spawns new thread for task? ),2)您可以测试列表到文件逻辑的实际写入,而与如何将其创建为异步任务无关,并且 3)不要使用 FileWriter 直接使用,但只需使用 Writer,这样您就可以在测试时进行模拟,避免在单元测试中实际写入/读取文件,并在需要时将此类练习留给集成测试.

关于java - TestNg 多线程问题。 TestNg 不尊重子线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37997895/

相关文章:

java - 如何保护程序在中断时不丢失数据?

c# - 您将如何更改我用 C# 编写的 Heartbeat 进程?

java - 我如何动态安排测试由 TestNG 运行?

java - 在 TestNG 中运行 Java 单元测试时消除对 testng.xml 的需求

java - hibernate 期待 "all",发现 'JOIN'

java - 确定当前正在使用哪个数组列表?

java - GCP 发布订阅 :Creating a Configuration Class to publish message

c# - 内存屏障后和互锁操作后内存缓存一致性的时间

java - 我的 DataProvider 没有被调用

Java : multi threading not working