【问题标题】:What is the difference between @BeforeClass and Spring @TestExecutionListener beforeTestClass()@BeforeClass 和 Spring @TestExecutionListener beforeTestClass() 有什么区别
【发布时间】:2025-11-23 20:15:01
【问题描述】:

使用 JUnit @BeforeClass 和 Spring @TestExecutionListener beforeTestClass(TestContext testContext) "hook" 有什么区别?如果有区别,在什么情况下使用哪一个?

Maven 依赖项:
弹簧芯:3.0.6.RELEASE
弹簧上下文:3.0.6.RELEASE
弹簧测试:3.0.6.RELEASE
spring-data-commons-core:1.2.0.M1
spring-data-mongodb:1.0.0.M4
mongo-java-driver:2.7.3
junit:4.9
cglib:2.2

使用 JUnit @BeforeClass 注解:

import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;

@ContextConfiguration(locations = { "classpath:test-config.xml" })
public class TestNothing extends AbstractJUnit4SpringContextTests {

    @Autowired
    PersonRepository repo;

    @BeforeClass
    public static void runBefore() {
        System.out.println("@BeforeClass: set up.");
    }

    @Test
    public void testInit() {
        Assert.assertTrue(repo.findAll().size() == 0 );
    }
}

=> @BeforeClass: set up.
=> Process finished with exit code 0

使用 Spring 钩子:

(1) 覆盖 beforeTestClass(TextContext testContext):

import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.AbstractTestExecutionListener;

public class BeforeClassHook extends AbstractTestExecutionListener {

    public BeforeClassHook() { }

    @Override
    public void beforeTestClass(TestContext testContext) {
        System.out.println("BeforeClassHook.beforeTestClass(): set up.");
    }
}

(2) 使用@TestExecutionListeners 注解:

import org.springframework.test.context.TestExecutionListeners;  
// other imports are the same    

@ContextConfiguration(locations = { "classpath:test-config.xml" })
@TestExecutionListeners(BeforeClassHook.class)
public class TestNothing extends AbstractJUnit4SpringContextTests {

    @Autowired
    PersonRepository repo;

    @Test
    public void testInit() {
        Assert.assertTrue(repo.findAll().size() == 0 );
    }
}

=> BeforeClassHook.beforeTestClass(): set up.
=> Process finished with exit code 0

【问题讨论】:

    标签: junit4 spring-test


    【解决方案1】:

    TestExecutionListeners 是一种外部化可重用代码的方法,仪器您的测试。

    因此,如果您实施 TestExecutionListener,您可以在测试类层次结构和项目之间重用它,具体取决于您的需要。

    另一方面,@BeforeClass 方法自然只能在单个测试类层次结构中使用。

    但是请注意,JUnit 也支持Rules:如果您实现org.junit.rules.TestRule,您可以将其声明为@ClassRule 以实现相同的目的......还有一个额外的好处是可以重用JUnit Rule像春天一样TestExecutionListener

    所以这真的取决于你的用例。如果您只需要在单个测试类或单个测试类层次结构中使用“类前”功能,那么您最好采用仅实现@BeforeClass 方法的简单路线。但是,如果您预见到在不同的测试类层次结构或跨项目中需要“类前”功能,您应该考虑实现自定义 TestExecutionListener 或 JUnit 规则。

    Spring TestExecutionListener 优于 JUnit 规则的好处是 TestExecutionListener 可以访问 TestContext,因此可以访问 JUnit 规则无法访问的 Spring ApplicationContext。此外,TestExecutionListener 可以是 automatically discoveredordered

    相关资源

    问候,

    Sam(Spring TestContext 框架的作者)

    【讨论】:

    • 有没有办法设置听者的顺序? (例如,我想在加载 spring 上下文之前运行一些代码)
    • 是的,当您在测试类上声明@TestExecutionListeners 时,您可以控制监听器的顺序。请参阅我的 Spring 3.1 and MVC Testing Support 演示文稿中的幻灯片 27-33,并查阅 Javadoc 以获取 @TestExecutionListeners
    • 刚刚阅读了这两个参考资料,但我没有看到与订单相关的任何内容。它们是否应该按照您在注释中声明它们的顺序运行?
    • 是的,TestContextManager 将它们维护为List<TestExecutionListener> testExecutionListeners,这是一个有序列表,它是根据通过@TestExecutionListeners 声明侦听器的顺序构造的。
    • 如果你使用监听器的继承呢?
    【解决方案2】:

    @BeforeClass 的第一个解决方案没有加载应用程序上下文。我确实扩展了 AbstractJUnit4SpringContextTests 并定义了 @ContextConfiguration。 我认为listner 是在@beforeclass 方法之前加载上下文的唯一方法。或者更好地扩展 SpringJUnit4ClassRunner 类,如 here

    【讨论】:

      最近更新 更多