在Junit 5中是否可以将Java功能接口实现(例如Supplier)用作MethodSource?

时间:2019-12-10 08:56:53

标签: java junit5 functional-interface

正在运行集成测试,我将其参数存储为diffrent文件内的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]

2 个答案:

答案 0 :(得分:3)

不,目前您所描述的内容似乎不可能。

MethodSource的文档对此并不十分清楚,但是查看its JavaDoc可能会提供一些见解:

  外部类中的

工厂方法必须由完全限定的方法名称引用,例如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类似乎不包含任何用于评估方法后的其他调用的功能,因此它将String视为标准方法名称。

也许您会从按照this answer创建自己的ArgumentsProvider中受益?

正如评论者所指出的那样,也许Dynamic Tests也可能适用于您的用例。

答案 1 :(得分:2)

此外,您还可以轻松创建自己的@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
}