2013-03-29 14 views
13

Ich möchte eine benutzerdefinierte TestExecutionListener in Kombination mit SpringJUnit4ClassRunner verwenden, um eine Liquibase-Schema-Setup auf meiner Test-Datenbank auszuführen. Meine TestExecutionListener funktioniert gut, aber wenn ich die Annotation auf meiner Klasse verwenden, funktioniert die Injektion des DAO unter Test nicht mehr, zumindest ist die Instanz null.Spring-Test-Injektion funktioniert nicht bei Verwendung von 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 
     ... 
    } 
} 

Der Hörer ist ziemlich einfach:

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

} 

keine Fehler im Protokoll Es gibt nur ein NullPointerException in meinem Test. Ich sehe nicht, wie sich die Verwendung meiner TestExecutionListener auf die Autowirkung oder Einspritzung auswirkt.

Antwort

20

Ich habe mir die Spring DEBUG Logs angeschaut und herausgefunden, dass Spring einen DependencyInjectionTestExecutionListener einrichtet, wenn ich meinen eigenen TestExecutionListener weglasse. Beim Kommentieren des Tests mit @TestExecutionListeners wird der Listener überschrieben.

So habe ich die DependencyInjectionTestExecutionListener nur explizit mit meiner Gewohnheit ein und alles funktioniert:

@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: Das Verhalten wird here dokumentiert.

... Alternativ können Sie Dependency Injection ganz explizit die Konfiguration Ihrer Klasse mit @TestExecutionListeners und Weglassen DependencyInjectionTestExecutionListener.class aus der Liste der Hörer deaktivieren.

+1

Das ist richtig: Wenn Sie einen benutzerdefinierten 'TestExecutionListener' über '@ TestExecutionListeners' angeben, überschreiben Sie implizit alle Standard-TestExecutionListeners. Zugegeben, diese Funktionalität ist vielleicht nicht so gut dokumentiert. Sie können also ein JIRA-Problem öffnen, um eine Verbesserung der Dokumentation zu beantragen. ;) –

+1

@SamBrannen: Eigentlich ist das dokumentiert - vielleicht etwas implizit. Siehe meine aktualisierte Antwort. – nansen

+2

Ich kenne den Text sehr gut, den du zitiert hast, seit ich ihn geschrieben habe. ;) Aber ... das beschreibt nicht explizit das Szenario, dem Sie begegnet sind. Deshalb habe ich vorgeschlagen, ein JIRA-Ticket zu öffnen, um die Dokumentation zu verbessern. –

3

würde ich empfehlen, nur zu prüfen, so etwas wie tun:

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

, so dass Sie nicht wissen müssen, welche Hörer erforderlich sind. Ich empfehle diesen Ansatz, weil ein paar Minuten mit SpringBoot gekämpft haben, die versuchen, es gerade mit DependencyInjectionTestExecutionListener.class in Ordnung zu bringen.