What is the difference between @BeforeClass and Spring @TestExecutionListener beforeTestClass()

StackOverflow https://stackoverflow.com/questions/12404636

  •  01-07-2021
  •  | 
  •  

Pregunta

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

Using JUnit @BeforeClass annotation:

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

Using the Spring hook:

(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
¿Fue útil?

Solución

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)

Otros consejos

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top