I want to use a custom TestExecutionListener
in combination with SpringJUnit4ClassRunner
to run a Liquibase schema setup on my test database. My TestExecutionListener
works fine but when I use the annotation on my class the injection of the DAO under test no longer works, at least the instance is null.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/applicationContext-test.xml" })
@TestExecutionListeners({ LiquibaseTestExecutionListener.class })
@LiquibaseChangeSet(changeSetLocations={"liquibase/v001/createTables.xml"})
public class DeviceDAOTest {
...
@Inject
DeviceDAO deviceDAO;
@Test
public void findByCategory_categoryHasSubCategories_returnsAllDescendantsDevices() {
List<Device> devices = deviceDAO.findByCategory(1); // deviceDAO null -> NPE
...
}
}
The listener is fairly simple:
public class LiquibaseTestExecutionListener extends AbstractTestExecutionListener {
@Override
public void beforeTestClass(TestContext testContext) throws Exception {
final LiquibaseChangeSet annotation = AnnotationUtils.findAnnotation(testContext.getTestClass(),
LiquibaseChangeSet.class);
if (annotation != null) {
executeChangesets(testContext, annotation.changeSetLocations());
}
}
private void executeChangesets(TestContext testContext, String[] changeSetLocation) throws SQLException,
LiquibaseException {
for (String location : changeSetLocation) {
DataSource datasource = testContext.getApplicationContext().getBean(DataSource.class);
DatabaseConnection database = new JdbcConnection(datasource.getConnection());
Liquibase liquibase = new Liquibase(location, new FileSystemResourceAccessor(), database);
liquibase.update(null);
}
}
}
There are no errors in the log, just a NullPointerException
in my test. I don't see how the use of my TestExecutionListener
affects the autowiring or injection.
I had a look at the spring DEBUG logs and found that when I omit my own TestExecutionListener spring sets a DependencyInjectionTestExecutionListener in place. When annotating the test with @TestExecutionListeners that listener gets overwritten.
So I just added the DependencyInjectionTestExecutionListener explicitly with my custom one and everything works fine:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/applicationContext-test.xml" })
@TestExecutionListeners(listeners = { LiquibaseTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class })
@LiquibaseChangeSet(changeSetLocations = { "liquibase/v001/createTables.xml" })
public class DeviceDAOTest {
...
UPDATE: The behavior is documented here.
... Alternatively, you can disable dependency injection altogether by explicitly configuring your class with @TestExecutionListeners and omitting DependencyInjectionTestExecutionListener.class from the list of listeners.
I would recommend to consider just doing something like:
@TestExecutionListeners(
mergeMode =TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS,
listeners = {MySuperfancyListener.class}
)
so that you do not need to know which listeners are required. I recommend this approach because a struggled a few minutes with SpringBoot trying to make it working right just by using DependencyInjectionTestExecutionListener.class
.
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