9

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

Maven 依赖项:
spring-core:3.0.6.RELEASE
spring-context:3.0.6.RELEASE
spring-test: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

使用弹簧钩:

(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
4

2 回答 2

21

TestExecutionListeners are a way to externalize reusable code that instruments your tests.

As such, if you implement a TestExecutionListener you can reuse it across test class hierarchies and potentially across projects, depending on your needs.

On the flip side, a @BeforeClass method can naturally only be used within a single test class hierarchy.

Note, however, that JUnit also supports Rules: if you implement org.junit.rules.TestRule you can declare it as a @ClassRule to achieve the same thing... with the added benefit that a JUnit Rule can be reused just like a Spring TestExecutionListener.

So it really depends on your use case. If you only need to use the "before class" functionality in a single test class or a single test class hierarchy, then you'd be better off going the simple route of just implementing a @BeforeClass method. However, if you foresee that you will need the "before class" functionality in different test class hierarchies or across projects, you should consider implementing a custom TestExecutionListener or JUnit Rule.

The benefit of a Spring TestExecutionListener over a JUnit Rule is that a TestExecutionListener has access to the TestContext and therefore access to the Spring ApplicationContext which a JUnit Rule would not have access to. Furthermore, a TestExecutionListener can be automatically discovered and ordered.

Related Resources:

Regards,

Sam (author of the Spring TestContext Framework)

于 2012-10-04T16:44:31.893 回答
2

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

于 2013-09-16T23:35:39.763 回答