JUnit ClassRule 在 Spring 引导应用程序关闭之前执行代码

JUnit ClassRule executes code before Spring Boot application shut down

我正在 运行 Spring 启动集成测试 org.springframework.boot.test.context.SpringBootTest

我已经编写了一个 JUnit 4 org.junit.rules.TestRule,我正在使用它 org.junit.ClassRule

看起来像这样:

public class MyRule implements TestRule {

    public Statement apply(final Statement statement, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                // do something
                try {
                    statement.evaluate();
                } finally {
                   // clean up
                }

            }
        };
    }

}

不幸的是,//清理代码在 Spring 引导上下文关闭之前执行。

Spring 应用程序关闭后,我必须将代码放在哪里才能执行它?

似乎所有 ClassRule 的代码都首先执行,并且 Spring 上下文在 JVM 终止之前被拆除(另请参阅 https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ConfigurableApplicationContext.html#registerShutdownHook--)。

关于 spring 的测试,我建议使用 Spring 测试执行侦听器。

规则是 JUnit 的特定功能,并且由于 spring 作为 Runner (@RunWith(SpringRunner.class)) 与 JUnit 集成,它们可能会产生干扰。

所以,回到那些测试执行监听器。基本上它是一个由 Spring 本身管理的侦听器,它提供了测试生命周期的挂钩,您可以在其中清理代码 这是一个例子:

public class MySampleListener implements TestExecutionListener {
   @Override
   public void beforeTestClass(TestContext testContext) throws Exception {
      System.out.println("beforeTestClass");
   }

   @Override
   public void prepareTestInstance(TestContext testContext) throws Exception {
      System.out.println("prepareTestInstance");
   }

   @Override
   public void beforeTestMethod(TestContext testContext) throws Exception {
       System.out.println("beforeTestMethod");
   }

   @Override
   public void afterTestMethod(TestContext testContext) throws Exception {
       System.out.println("afterTestMethod");
   }

   @Override
   public void afterTestClass(TestContext testContext) throws Exception {
       System.out.println("afterTestClass");
   }
}

如果您不需要所有方法,您可以使用 org.springframework.test.context.support.AbstractTestExecutionListener,它为所有这些方法提供了一个空的实现。

现在,在测试中你提供了一个注解 @TestExecutionListeners:

@RunWith(SpringRunner.class)
... // stuff like @ContextConfiguration
@TestExecutionListeners(value = {MySampleListener.class, ...})
  public class MySampleTest {


   @Test
   public void testFoo() {
     //test me
   }

}

如果你想合并spring默认运行的其他监听器,你可以使用这个注解如下:

@TestExecutionListeners(value = MySampleListener.class, mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS)