我如何在 Spring 启动之前在 JUnit 中 运行 编写代码?

How can I run code in JUnit before Spring starts?

如何在 Spring 开始之前 运行 在我的 @RunWith(SpringRunner.class) @SpringBootTest(classes = {...}) JUnit 测试中编写代码?

This question has been asked several times (e.g. 1, ) but was always "solved" by some configuration recommendation or other, never with a universal answer. Kindly don't question what I am about to do in that code but simply suggest a clean way to do it.

到目前为止尝试过但失败了:

扩展 SpringJUnit4ClassRunner 得到一个 class 其构造函数可以 运行 在初始化 Spring 之前自定义代码。失败,因为必须首先调用 super(testClass) 并且已经做了很多阻碍的事情。

扩展 Runner 以获得委托给 SpringRunner 而不是继承它的 class。在实际实例化 SpringRunner 之前,此 class 可以在其构造函数中 运行 自定义代码。但是,此设置失败并显示模糊的错误消息,例如 java.lang.NoClassDefFoundError: javax/servlet/SessionCookieConfig。 "Obscure" 因为我的测试没有网络配置,因此不应干扰会话和 cookie。

添加在 Spring 加载其上下文之前触发的 ApplicationContextInitializer。这些东西很容易添加到实际的@SpringApplication 中,但很难添加到 Junit 中。他们在这个过程中也很晚,很多Spring已经开始了。

一种方法是省略 SpringRunner 并使用 the equivalent combination of SpringClassRule and SpringMethodRule instead. Then you can wrap the SpringClassRule 并在它开始之前做你的事情:

public class SomeSpringTest {

    @ClassRule
    public static final TestRule TestRule = new TestRule() {
            private final SpringClassRule springClassRule =
                new SpringClassRule();

            @Override
            public Statement apply(Statement statement, Description description) {
                System.out.println("Before everything Spring does");
                return springClassRule.apply(statement, description);
            }
        };

    @Rule
    public final SpringMethodRule springMethodRule = new SpringMethodRule();

    @Test
    public void test() {
        // ...
    }
}

(使用 5.1 测试。4.RELEASE Spring verison)

我不认为你能得到比这更多的 "before"。至于其他选项,您还可以查看 @BootstrapWith and @TestExecutionListeners 注释。

补充 jannis 对问题的评论,创建替代 JUnit 运行器并让它委托给 SpringRunner 的选项 工作:

public class AlternativeSpringRunner extends Runner {

    private SpringRunner springRunner;

    public AlternativeSpringRunner(Class testClass) {
        doSomethingBeforeSpringStarts();
        springRunner = new SpringRunner(testClass);
    }

    private doSomethingBeforeSpringStarts() {
        // whatever
    }

    public Description getDescription() {
        return springRunner.getDescription();
    }

    public void run(RunNotifier notifier) {
        springRunner.run(notifier);
    }

}

基于 spring-test 4.3.9.RELEASE,我不得不覆盖 spring-corespring-tx,再加上 javax.servletservlet-api使这项工作的版本。