2016-03-30 6 views
5

Ich habe in @ComponentScan Probleme mit @Configuration Klassen für Tests - nämlich, die @ComponentScan zieht unbeabsichtigt @Configuration während Integrationstests.Ausschließen der Konfiguration in Testklassen von @ComponentScan

Zum Beispiel, sagen Sie einige globale config in src/main/java haben, die innerhalb com.example.service in Komponenten zieht, com.example.config.GlobalConfiguration:

package com.example.config; 
... 
@Configuration 
@ComponentScan(basePackageClasses = ServiceA.class) 
public class GlobalConfiguration { 
    ... 
} 

Es ist beabsichtigt ist in zwei Dienste zu ziehen, com.example.services.ServiceA und com.example.services.ServiceB, kommentierte mit @Component und @Profile("!test") (der Kürze halber weggelassen).

dann in src/test/java, com.example.services.ServiceATest:

package com.example.services; 
... 
@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = ServiceATest.ServiceATestConfiguration.class) 
public class ServiceATest { 
    ... 
    @Configuration 
    public static class ServiceATestConfiguration { 
     @Bean 
     public ServiceA serviceA() { 
      return ServiceA(somemocking...); 
     } 
    } 
} 

Und auch com.example.ServiceBIntegrationTest, die in GlobalConfiguration.class zu ziehen, um braucht ein Integrationstest zu sein, aber immer noch vermeidet mit @ActiveProfiles("test") in gefährlichen Implementierungen ziehen:

package com.example.services; 
... 
@RunWith(SpringJUnit4ClassRunner.class) 
@ActiveProfiles("test") 
@ContextConfiguration(classes = {GlobalConfiguration.class, ServiceBIntegrationTest.ServiceBIntegrationTestConfiguration.class}) 
public class ServiceBIntegrationTest { 
    ... 
    @Configuration 
    public static class ServiceBIntegrationTestConfiguration { 
     @Bean 
     public ServiceB serviceB() { 
      return ServiceB(somemocking...); 
     } 
    } 
} 

die offensichtliche Absicht der ServiceBIntegrationTest ist in der kompletten src/main/java Anwendungskonfiguration über GlobalConfiguration ausschließen, gefährlich zu ziehen Komponenten über @ActiveProfiles("test") und ersetzen diese ausgeschlossenen Komponenten durch eigene Implementierungen. Während der Tests werden jedoch die Namensräume und src/test/java kombiniert, so dass GlobalConfiguration@ComponentScan mehr im Klassenpfad findet als normalerweise - nämlich die ServiceA Bean, die in ServiceA.ServiceATestConfiguration definiert ist. Das könnte leicht zu Konflikten und unbeabsichtigten Ergebnissen führen.

Jetzt könnten Sie etwas auf GlobalConfiguration wie @ComponentScan(..., excludeFilters= @ComponentScan.Filter(type = FilterType.REGEX, pattern = "\\.*(T|t)est\\.*")) tun, aber das hat seine eigenen Probleme. Sich auf Namenskonventionen zu verlassen ist ziemlich spröde; Dennoch, auch wenn Sie eine @TestConfiguration Annotation zurückgenommen und FilterType.ANNOTATION verwendet haben, würden Sie effektiv Ihre src/main/java Ihrer src/test/java bewusst machen, die es nicht sein sollte, IMO (siehe Hinweis unten).

So wie es aussieht, habe ich mein Problem mit einem zusätzlichen Profil gelöst. Unter ServiceA füge ich einen eindeutigen Profilnamen hinzu - so dass seine Profilanmerkung etwa wie @ActiveProfiles("test,serviceatest") aussieht. Dann, unter ServiceATest.ServiceATestConfiguration, füge ich die Annotation @Profile("serviceatest") hinzu. Dies begrenzt effektiv den Umfang des ServiceATestConfiguration mit relativ wenig Aufwand, aber es scheint, als ob entweder:

a) Ich @ComponentScan falsch verwenden, oder

b) Es sollte für den Umgang mit diesem Problem ein viel sauberes Muster seiner

Was ist das?


note: ja, die App ist Test bewusst, weil es @Profile("!test") ist, aber ich würde behaupten, die Anwendung leicht Test-bewusst zu machen, gegen falsche Ressourcennutzung zu schützen und machen es Test-aware, um sicherzustellen, Die Richtigkeit der Tests sind sehr unterschiedliche Dinge.

Antwort

1

Ich sehe Sie versuchen, Spring Bohnen während des Integrationstests zu fälschen.Wenn Sie @Profile und Annotation mit @Primary Annotation kombinieren, sollten die meisten Ihrer Kopfschmerzen verschwinden und Sie sollten keine Produktionsbeans mit @Profile("!test") markieren müssen.

Ich schrieb eine blog post on the topic mit Github examples.

Reaktion auf Kommentar:

Nach Paketstruktur. Beim Komponentenscan werden alle Pakete im aktuellen Paket und in den Unterpaketen gescannt. Wenn Sie keine Beans scannen möchten, passen Sie einfach Ihre Paketstruktur an, so wie diese Bean nicht unter Ihrem Komponentenscan-Regenschirm wäre.

Spring unterscheidet keine Pakete von src/test/java oder src/main/java. Der Versuch, Produktionsbohnen mit @Profile("!test") auszuschließen, ist Designgeruch. Du solltest es vermeiden. Ich würde vorschlagen, eine Chance zu geben, vom genannten blog anzufangen.

Beachten Sie, dass Sie beim Überschreiben der Bean mit der @ Primary-Annotation möglicherweise @DirtiesContext Annotation verwenden müssen, um ein reines Blatt für andere Tests zu erhalten.

+1

Ja, es gibt einige Vorteile zu diesem Muster, aber das ist nicht, was meine Frage ist. Ich frage, wie man den Umfang der Konfiguration innerhalb eines Komponenten-gescannten Pakets am besten begrenzt. – jwilner

+1

Das Ändern der Verpackung würde mit dem lokalen Scoping des Pakets kollidieren, was offensichtlich für das Testen wichtig ist. Dies ist nicht zufriedenstellend. – jwilner

Verwandte Themen