是否可以在 Junit 5 中使用 Java 功能接口实现(例如 Supplier)作为 MethodSource?
Is it possible to use Java functional interface implementation (such as the Supplier) as a MethodSource in Junit 5?
运行 集成测试 我将它们的参数存储为不同文件中的 json。这些文件存储不同的测试用例,然后用不同的方法进行测试。
我想知道是否可以创建一个通用的读取文件方法,例如这个方法:
static Stream<Arguments> argumentsOf(String fileName) {
Path argumentsFilePath = Paths.get(ARGUMENTS_FILES_DIRECTORY + fileName);
//read and return arguments stored in a file
}
加上像这样的功能界面:
static Supplier<Stream<Arguments>> anExampleArgument =
() -> argumentsOf("some_test_case_argument.json");
所以我可以这样做:
@ParameterizedTest
@MethodSource("anExampleArgument.get")
void test1(String exampleArgument) {
//...
}
我找不到有关此场景的任何信息。上面看到的示例代码导致
org.junit.platform.commons.JUnitException: Could not find factory method [anExampleArgument.get] in class [com.company.ExampleIntegrationTest]
不,目前你所描述的似乎是不可能的。
MethodSource are not very clear on this, but looking at its JavaDoc 的文档可能会提供一些见解:
Factory methods in external classes must be referenced by fully qualified method name — for example, com.example.StringsProviders#blankStrings
.
引发您看到的异常的代码是 here:
private Method getMethod(Class<?> clazz, String methodName) {
return ReflectionUtils.findMethod(clazz, methodName).orElseThrow(() -> new JUnitException(
format("Could not find factory method [%s] in class [%s]", methodName, clazz.getName())));
}
遗憾的是,他们的 ReflectionUtils class 似乎不包含任何用于评估方法后附加调用的功能,因此它将您的字符串视为完全限定的方法名称。
也许您可以根据 创建自己的 ArgumentsProvider
?
正如评论者指出的那样,也许 Dynamic Tests 也适用于您的用例。
此外,您可以很容易地创建自己的 @FileSource
注释:
@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@ArgumentsSource(FileArgumentsProvider.class)
public @interface FileSource {
String[] value() default "";
}
连同 ArgumentsProvider
:
public class FileArgumentsProvider implements ArgumentsProvider, AnnotationConsumer<FileSource> {
private String[] fileNames;
@Override
public void accept(FileSource fileSource) {
this.fileNames = fileSource.value();
}
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Arrays.stream(fileNames).map(this::readFile).map(Arguments::of);
}
private String readFile(String fileName) {
return "the actual content of the file";
}
}
并像这样使用它:
@ParameterizedTest
@FileSource({"test_case_1.json", "test_case_2.json", "test_case_3.json"})
void test(String fileContent) {
// Your test code
}
运行 集成测试 我将它们的参数存储为不同文件中的 json。这些文件存储不同的测试用例,然后用不同的方法进行测试。
我想知道是否可以创建一个通用的读取文件方法,例如这个方法:
static Stream<Arguments> argumentsOf(String fileName) {
Path argumentsFilePath = Paths.get(ARGUMENTS_FILES_DIRECTORY + fileName);
//read and return arguments stored in a file
}
加上像这样的功能界面:
static Supplier<Stream<Arguments>> anExampleArgument =
() -> argumentsOf("some_test_case_argument.json");
所以我可以这样做:
@ParameterizedTest
@MethodSource("anExampleArgument.get")
void test1(String exampleArgument) {
//...
}
我找不到有关此场景的任何信息。上面看到的示例代码导致
org.junit.platform.commons.JUnitException: Could not find factory method [anExampleArgument.get] in class [com.company.ExampleIntegrationTest]
不,目前你所描述的似乎是不可能的。
MethodSource are not very clear on this, but looking at its JavaDoc 的文档可能会提供一些见解:
Factory methods in external classes must be referenced by fully qualified method name — for example,
com.example.StringsProviders#blankStrings
.
引发您看到的异常的代码是 here:
private Method getMethod(Class<?> clazz, String methodName) {
return ReflectionUtils.findMethod(clazz, methodName).orElseThrow(() -> new JUnitException(
format("Could not find factory method [%s] in class [%s]", methodName, clazz.getName())));
}
遗憾的是,他们的 ReflectionUtils class 似乎不包含任何用于评估方法后附加调用的功能,因此它将您的字符串视为完全限定的方法名称。
也许您可以根据 ArgumentsProvider
?
正如评论者指出的那样,也许 Dynamic Tests 也适用于您的用例。
此外,您可以很容易地创建自己的 @FileSource
注释:
@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@ArgumentsSource(FileArgumentsProvider.class)
public @interface FileSource {
String[] value() default "";
}
连同 ArgumentsProvider
:
public class FileArgumentsProvider implements ArgumentsProvider, AnnotationConsumer<FileSource> {
private String[] fileNames;
@Override
public void accept(FileSource fileSource) {
this.fileNames = fileSource.value();
}
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Arrays.stream(fileNames).map(this::readFile).map(Arguments::of);
}
private String readFile(String fileName) {
return "the actual content of the file";
}
}
并像这样使用它:
@ParameterizedTest
@FileSource({"test_case_1.json", "test_case_2.json", "test_case_3.json"})
void test(String fileContent) {
// Your test code
}