我正在编写参数化测试,其中测试类和方法是并行运行的.下面是配置.

junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.mode.classes.default = concurrent
junit.jupiter.execution.parallel.config.dynamic.factor = 2

测试片段如下-

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

@ExtendWith(SimpleCallbackListener.class)
public class HelloWorldTest {
    private static final Map<String, List<TestData>> testDataMap;

    static {
        testDataMap = TestsConfigManager.readTestConfig("test-data");
    }

    private static List<Object[]> data() {
        final List<Object[]> testDataList = prepareTestData(testDataMap);
        return testDataList;
    }

    @ParameterizedTest(name = "{index}: {0}")
    @MethodSource("data")
    @Tag("regression")
    public void testMethodName(
            final String expected,
            final String actual
    ) {
        // test code goes here
    }
}

SimpleCallbackListener的数字如下-

public class SimpleCallbackListener implements BeforeAllCallback, ExtensionContext.Store.CloseableResource {
    /**
     * gatekeeper to prevent multiple Threads within the same routine
     */
    private static final Lock LOCK = new ReentrantLock();
    private static boolean started = false;
    private Instant startTime;

    @Override
    public void beforeAll(final ExtensionContext context) {
        LOCK.lock();
        try {
            if (!started) {
                startTime = Instant.now();
                requireApplicationInitializer();
                // The following line registers a callback hook when the root test context is shut down
                context.getRoot().getStore(GLOBAL).put(this.getClass().getName(), this);
                started = true;
            }
        } finally {
            LOCK.unlock();
        }
    }
}

问题

此设置导致以下间歇性异常.

org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter ... in method ...
    at java.base@17.0.7/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:194)
    at java.base@17.0.7/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
    at java.base@17.0.7/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
    at java.base@17.0.7/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
    at java.base@17.0.7/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
    at java.base@17.0.7/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)

查看了建议的答案-

  1. https://stackoverflow.com/questions/65934665/why-do-i-have-parameterresolutionexception-when-i-dont-even-use-parametrized-tehttps://stackoverflow.com/questions/65934665/why-do-i-have-parameterresolutionexception-when-i-dont-even-use-parametrized-te
  2. Junit 5 - No ParameterResolver registered for parameter

推荐答案

我找到了根本原因.

问题出在以下方法上.

public static List<Object[]> prepareTestData() {
    final List<Object[]> testDataList = new ArrayList<>();
    
    testDataMap
        .entrySet()
        .parallelStream()
        .forEach(entry -> {
            final String storeAlias = entry.getKey();
            final List<TestData> testDataList = entry.getValue();
            final List<Object[]> list = testDataList
                    .stream()
                    ...
                    .map(testData -> new Object[]{someObj1, someObj2})
                    .toList();
            testDataList.addAll(list);
        });
}

在这里,我试图同时将元素添加到ArrayList. 但是,后来我意识到ArrayList不是线程安全的,因此这造成了问题.

解决方案?

我用了CopyOnWriteArrayList美元.

Java相关问答推荐

我可以在regex中的字符类中放置断言吗?

Junit with Mockito for java

是否保证在事务性块的末尾标记违反约束?

具有阻塞方法的开源库是否应该为执行提供异步选项?

GetChildren().emoveAll()不会删除 node

使用多个RemoteDatabase对象的一个线程

继续收到错误SQLJDBC EXCEPTION执行";org.springframework.dao.InvalidDataAccessResourceUsageException:&

如何在构建Gradle项目时排除com.google.guava依赖项的一个变体

Java Telnet客户端重复的IAC符号

Android应用程序为错误的显示类型 Select 尺寸文件

找出承载Cargo 的最小成本

JavaFX:无论何时显示应用程序,如何更改组件/ node 位置?

如何处理两个几乎相同的XSD文件?

从12小时开始的日期模式

有没有办法知道在合并中执行了什么操作?

JavaFX,GridPane:在GridPane的列中生成元素将保持所有列的宽度

为什么没有加载java.se模块?

为什么我的登录终结点不能被任何请求访问?

PhantomReference无法访问时会发生什么?

java.lang.ClassCastException:com.google.firebase.FirebaseException无法转换为com.google.fire base.auth.FirebaseAuthException