2013-03-29 14 views
13

Desidero utilizzare un valore personalizzato TestExecutionListener in combinazione con SpringJUnit4ClassRunner per eseguire un'impostazione dello schema Liquibase sul mio database di test. Il mio TestExecutionListener funziona bene ma quando uso l'annotazione sulla mia classe l'iniezione del DAO sotto test non funziona più, almeno l'istanza è nullo.Iniezione test di primavera non funziona quando si utilizza TestExecutionListener

@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 
     ... 
    } 
} 

L'ascoltatore è abbastanza semplice:

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); 
     } 
    } 

} 

Non ci sono errori nel registro, solo un NullPointerException nel mio test. Non vedo come l'uso del mio TestExecutionListener influisca sul processo di autowiring o sull'iniezione.

risposta

20

Ho dato un'occhiata ai registri di DEBUG di primavera e ho scoperto che quando ometto il mio TestExecutionListener molla imposta un DependencyInjectionTestExecutionListener in posizione. Quando si annota il test con @TestExecutionListeners, il listener viene sovrascritto.

Così ho solo aggiunto il DependencyInjectionTestExecutionListener esplicitamente con mia abitudine uno e tutto funziona bene:

@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: Il comportamento è documentato here.

... In alternativa, è possibile disattivare l'iniezione di dipendenza del tutto configurando in modo esplicito la classe con @TestExecutionListeners e omettendo DependencyInjectionTestExecutionListener.class dalla lista degli ascoltatori.

+1

Questo è corretto: se si specifica un 'TestExecutionListener personalizzato tramite' @ TestExecutionListeners', si esegue l'override implicita di tutti i TestExecutionListeners predefiniti. Certo, questa funzionalità non è forse ben documentata. Quindi sentiti libero di aprire un problema JIRA per richiedere un miglioramento della documentazione. ;) –

+1

@SamBrannen: In realtà è documentato, forse in modo un po 'implicito. Vedi la mia risposta aggiornata. – nansen

+2

Sono ben consapevole del testo che hai citato da quando l'ho scritto. ;) Ma ... questo non descrive esplicitamente lo scenario che hai incontrato. Ecco perché ti ho suggerito di aprire un ticket JIRA per migliorare la documentazione. –

3

Suggerirei di prendere in considerazione solo facendo qualcosa di simile:

@TestExecutionListeners(
     mergeMode =TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS, 
     listeners = {MySuperfancyListener.class} 
) 

in modo che non avete bisogno di sapere che gli ascoltatori sono obbligatori. Raccomando questo approccio perché ho sofferto qualche minuto con SpringBoot che cercava di farlo funzionare proprio usando DependencyInjectionTestExecutionListener.class.

Problemi correlati