The org.springframework.test.context.junit4.SpringJUnit4ClassRunner class is another implementation of the JUnit TestRunner class which is used to enable various features of Spring for every run of the test class and every test within it. To use the features provided by the SpringJUnit4ClassRunner class, you need to mark the class using the RunWith annotation using SpringJUnit4ClassRunner as its parameter.
In addition to the custom test runner, you will want to mark the class with the ContextConfiguration annotation. The ContextConfiguration annotation is used to mark classes which will automatically read a Spring configuration file and use it to create an ApplicationContext. By default, this file located at <package path>/<test class name>-context.xml. Use the locations argument to over-ride.
The ApplicationContext used by the Spring-integrated test will only be loaded once for the whole test class. This behavior can be over-ridden by annotating a test method with the DirtiesContext annotation, which causes the ApplicationContext to be reloaded after the test method completes.
Test Property Injection
Fresh versions of the properties for the test, including the class under test, can be automatically injected for every test, either by name or type. A test class property marked with the Autowired annotation will be automatically set by type from the test's ApplicationContext. However, if there are multiple instances of the property's type, it could be better to set the property by name. The Resource is used to mark test class properties which should be set by name from the test's ApplicationContext.
Transaction Management
With the declaration of a TransactionManager bean, and the use of the Transactional annotation, transaction boundaries are declarative and are automatically managed. Simply fire up the test and forget about whether or not your integration test changed the state of the database you're using to test.
The Transactional annotation is used within transactional Spring tests to mark test classes and methods which should have a transactional nature applied to them. When used to annotate a test class, a transaction context will be created before each test method is executed. After each test method, the transaction will be rolled-back. This will add the overhead of creating and managing a transaction for every test method in that class, so it is usually better to annotate the test methods with @Transactional instead. This will cause a similar effect to annotating the class, but only annotated test methods will be transactional. Usage of this annotation requires a TransactionManager named transactionManager to be defined in the test's ApplicationContext.
Similar in purpose to the Before and After annotations provided by JUnit, methods decorated with either the BeforeTransaction or AfterTransaction annotation will be run before/after any test method which is affected by the Transactional annotation (i.e. all methods in a class decorated with @Transactional, or each annotated test method when marked individually. Methods annotated with the BeforeTransaction or AfterTransaction annotations must be public and return no value.
Integration Test Helper Classes
When using the SpringJUnit4ClassRunner, you're given access to the ApplicationContext instance and a simplified interface for interacting with your integration test database through JdbcTemplate/SimpleJdbcTemplate.
spring-testing-sample.java
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class ITSpringExample { @Resource Object dependencyByName; @Autowired String dependencyByType; @BeforeTransaction public void preTransaction() { System.out.println("before transaction"); } @AfterTransaction public void postTransaction() { System.out.println("after transaction"); } @Transactional @Test public void test1() { // before this test, a transaction will be created // after this test, the transaction will be rolled-back } @Test public void test2() { // no transaction will be created around this test } @DirtiesContext @Test public void test3() { dependencyByName = null; } }
Comments