如何在每个@Test 中为@BeforeEach 方法提供参数

How to provide Parameter for @BeforeEach method at each @Test

我正在用 JUnit 5 编写一些 JUnit 测试。在每次测试之前,我需要加载一个测试资源并用它初始化一些其他东西。为此,我编写了用 @BeforeEach 注释的 init 方法,因为除了每次测试要加载的资源应该不同之外,进度总是相同的。
我首先想到的是去掉@BeforeEach 注解,在init 方法中添加一个参数来指定应该加载哪个资源,然后在开始的每个测试中自己调用init 方法。

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

public class MyTest {
   private Object testResource;

   private void init(String resourcePath) {
      // actually load the resource and initialize some fields here
      this.testResource = "Loaded resource from: " + resourcePath;
   }

   @Test
   public void test0() {
      init("TestResource0");
      assertEquals("Loaded resource from: TestResource0", testResource);
   }

   @Test
   public void test1() {
      init("TestResource1");
      assertEquals("Loaded resource from: TestResource1", testResource);
   }

}

这样我觉得我正在破坏 JUnit 测试流程的整个结构,我担心这可能会在将来扩展测试时导致一些问题,例如一些花哨的元测试编程,我将依靠 JUnit 提供有关测试当前状态的正确信息。
所以我决定在init方法上保留要加载资源的参数,保留@BeforeEach注解。这样我就需要包含一个 ParameterResolverresolveParameter(ParameterContext, ExtensionContext)的实现我首先想到的是先找出要执行的是什么测试,return那个测试要加载的对应资源。

static class MyParamResolver implements ParameterResolver {

      @Override
      public Object resolveParameter(ParameterContext parameterContext,
                                     ExtensionContext extensionContext) throws ParameterResolutionException {

         String test = extensionContext.getRequiredTestMethod()
                                       .getName();

         switch (test) {
         case "test0":
            return "TestResource0";
         case "test1":
            return "TestResource1";
         }

         throw new ParameterResolutionException("Unknown test " + test);
      }

      @Override
      public boolean supportsParameter(ParameterContext parameterContext,
                                       ExtensionContext extensionContext) {
         return true;
      }

   }

我不喜欢那个解决方案,因为我首先没有安全性来确保名称的正确性由编译器确保,其次要加载的资源乍一看没有明显地连接到相应的测试。然后我认为以某种方式向直接附加到测试方法的注释提供资源路径会很好。类似的东西:

@Test("test0")
public void test0() {
    assertEquals("Loaded resource from: TestResource0", testResource);
}

@Test("test1")
public void test1() {
   assertEquals("Loaded resource from: TestResource1", testResource);
}

...

    @Override
    public Object resolveParameter(ParameterContext parameterContext,
                                   ExtensionContext extensionContext) {

        return extensionContext.getRequiredTestMethod()
                               .getAnnotation(Test.class)
                               .value();
     }

不幸的是,@Test 注释没有定义任何参数,在对 JUnit 文档进行一些研究之后,我在这里找不到任何其他适合的注释。我现在能想到的最好的事情是创建我自己的注释并将其放在每个测试方法上。但我也认为这是一个普遍的问题,无需自己重新发明 weel 就可以解决。我就是找不到任何东西。
有没有一种方便的方法来解决这个问题,不需要发明自己的注释。换句话说:是否有一种简单的方法可以保持代码质量和可读性来解决这个问题,只需使用已经存在的框架API?

我猜,您正在寻找 "container templates"。它们还不是木星的一部分。但是已经安排了 5.4:https://github.com/junit-team/junit5/issues/871

ParameterizedTest 当你有相同的测试步骤,但想用不同的参数执行它时很有用。事实似乎并非如此。您可以简单地使用 TestInfo 参数到 @BeforeEach 方法来处理您的情况。

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;

public class JUnitTest {

    @Test public void test1() {
        System.out.println("Test");
    }

    @BeforeEach public void f(TestInfo info) {
        System.out.println(info.getDisplayName());
    }
}