如何为自定义 ParameterResolver 实现创建测试?

How to create a test for a custom ParameterResolver implementation?

我创建了一个 ParameterResolver 实现,以便将参数注入我的测试方法。 我有一个场景,如果没有相应注释定义的一些适当参数,参数对象的实例化可能会失败并抛出异常。

  @TestScenario(homeDirName = "")
  @Test
  void ensureFailingWithoutProperHomeDirectory(LauncherRuntime launcher) {

    assertThrows(MissingPropertiesException.class,
                 () -> launcher.run());
  }

但是这个测试甚至在开始 运行 之前就失败了,并出现 ParameterResolutionException。

我想知道如何测试它。

由于您要测试 ParameterResolver 实现而不是 JUnit 引擎,因此单元测试的入口点应该是实现的 provideArguments 方法。 JUnit 捕获此方法抛出的每个异常并将其添加为新的 ParameterResolutionException 的原因。有两种可能的方法:

A) 如果您的实现应该调用 ExtensionContext 的多个方法,那么将这些方法与您的注释一起模拟。并调用您的实现的 provideArguments

B) 如果您的实现应仅使用 ExtensionContext 来获取注释并且不做任何值得测试的事情,那么将主要功能移动到自己的方法中(例如 accept(MyAnnotation))并测试此方法。例如,请参阅 here JUnit 开发人员如何将其用于 CVSSource 注释。

这是我的 ResourceFilesArgumentsProvider / ResourceFilesSource 注释的示例测试用例:

import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class ResourceFilesArgumentsProviderTest {

  @Test
  public void nonExistingDirectory() throws Exception {

    ResourceFilesSource annotation = resourceFiles("/non-existing-dir");

    AnnotatedElement annotatedElement = mock(AnnotatedElement.class);

    when(annotatedElement.getAnnotation(ResourceFilesSource.class))
      .thenReturn(annotation);

    ExtensionContext context = mock(ExtensionContext.class);
    when(context.getElement()).thenReturn(Optional.of(annotatedElement));
    when(context.getTestClass()).thenReturn(Optional.of(getClass()));

    assertThrows(NoSuchFileException.class, () -> provideArguments(context));
  }

  private Stream<Object[]> provideArguments(ExtensionContext context) throws Exception {
    ResourceFilesArgumentsProvider provider = new ResourceFilesArgumentsProvider();
    return provider.provideArguments(context).map(Arguments::get);
  }

  private ResourceFilesSource resourceFiles(String directory) {

    /* mock the annotation with Mockito, or alternatively create
     * an anonymous class with new ResourceFileSource() { ... }
     */
    ResourceFilesSource annotation = mock(ResourceFilesSource.class);
    when(annotation.directory()).thenReturn(directory);
    return annotation;
  }

}