Junit5自定义ArgumentsSource用于加载json数据作为ParameterizedTest的参数

7 阅读1分钟

Junit5自定义ArgumentsSource用于加载json数据作为ParameterizedTest的参数

实现方案

  1. 实现一个自定义注解MyJsonSource
  2. 实现对应的JsonFileArgumentsProvider

实现代码

/*
 * Ant Group
 * Copyright (c) 2004-2025 All Rights Reserved.
 */
package local.my.demo_jdk.t;

import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.*;
import org.junit.jupiter.params.support.ParameterDeclaration;
import org.junit.jupiter.params.support.ParameterDeclarations;

import java.lang.annotation.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;


@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@ArgumentsSource(MyJsonSource.JsonFileArgumentsProvider.class)
public @interface MyJsonSource {


    String[] value();

    class JsonFileArgumentsProvider extends AnnotationBasedArgumentsProvider {
        @Override
        protected Stream provideArguments(ParameterDeclarations parameters, ExtensionContext context,
                                                               MyJsonSource source) {
            var types = parameters.getAll().stream().map(ParameterDeclaration::getParameterType).toList();
            List argumentsList = new ArrayList<>();
            if (source.value() != null) {
                for (String sourceStr : source.value()) {
                    if (sourceStr == null || (sourceStr = sourceStr.trim()).isEmpty()) {
                        continue;
                    }
                    argumentsList.add(read(sourceStr, types));
                }
            }
            return argumentsList.stream();
        }

        private static String load(String sourceStr) {
            if (sourceStr.endsWith(&#34;.json&#34;) || sourceStr.endsWith(&#34;.json5&#34;) || sourceStr.endsWith(&#34;.jsonl&#34;)) {
                //文件
                sourceStr = ResourceUtil.readStr(sourceStr, StandardCharsets.UTF_8);
            }
            return sourceStr == null ? null : sourceStr.trim();
        }

        private static Arguments read(String sourceStr, List> types) {
            String value = load(sourceStr);
            if (value.startsWith(&#34;{&#34;)) {
                //直接写的JSON
                var j = JSONUtil.parse(value);
                return Arguments.of(j.toBean(types.getFirst()));
            } else if (value.startsWith(&#34;[&#34;)) {
                if (types.size() <= 1) {
                    if (types.getFirst().isAssignableFrom(List.class))
                        return Arguments.of(JSONUtil.toList(value, types.getFirst()));
                    else
                        return Arguments.of(((JSON) JSONUtil.parseArray(value).get(0)).toBean(types.getFirst()));
                } else {
                    var arr = JSONUtil.parseArray(value);
                    Object[] objs = new Object[types.size()];
                    for (int i = 0; i < Math.min(types.size(), arr.size()); i++) {
                        JSONUtil.toBean((JSON) arr.get(i), types.get(i), true);
                    }
                    return Arguments.of(objs);
                }
            } else 
                throw new RuntimeException(&#34;不支持的类型:&#34;+sourceStr);
        }
    }
}

测试

import org.junit.jupiter.params.ParameterizedTest

class MyTest {
    @ParameterizedTest
    @MyJsonSource([&#34;&#34;&#34;
{&#34;a&#34;:1}&#34;&#34;&#34;,
    //假设resources/test.json文件内容为{&#34;a&#34;:2}
            &#34;test.json&#34;])
    void test2(Map s) {
        println s
    }
}
/*
运行测试将输出
> Task :testClasses
[a:1]
[a:2]
> Task :test
Gv1Test > test2(Map) > [1] {a=1} PASSED
Gv1Test > test2(Map) > [2] {a=2} PASSED
*/