What is the difference between using JUnit @BeforeClass and the Spring @TestExecutionListener beforeTestClass(TestContext testContext) "hook"? If there is a difference, which one to use under which circumstances?
Maven Dependencies:
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
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) Override 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) Use @TestExecutionListeners annotation:
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
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)
The first solution with @BeforeClass doesn't have application context loaded. I did exteneded AbstractJUnit4SpringContextTests and defined @ContextConfiguration. I think listner is the only way to get context loaded before @beforeclass method. Or even better extending SpringJUnit4ClassRunner class as mentioned here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With