2016-07-06 14 views
2

Ich habe ein springboot app (v1.3.5)Frühling Boot Override-Schnittstelle im Test

Meine Hauptanwendung geht:

@SpringBootApplication 
@ComponentScan({"com.akrome"}) 
public class InboxCoreApplication { 
    public static void main(String[] args) { 
     SpringApplication.run(InboxCoreApplication.class, args); 
    } 
} 

Irgendwo in den Paketen habe ich ein Repo als Implementierung definiert:

@Repository 
public class CouchbaseServiceImpl implements CouchbaseService { 

Und woanders habe ich eine Klasse unter Verwendung dieser Schnittstelle:

Ich habe auch eine Testversion der Schnittstelle:

@Repository 
public class CouchbaseServiceTestImpl implements CouchbaseService { 

Jetzt. In meinem Test möchte ich einfach das Schnittstellen-Mapping auf die Test-Implementierung verweisen, während alles andere so bleibt, wie es beim Scannen der Haupt-Konfigurationskomponente definiert ist. Aber es geht weiter Bananen. Die nächstgelegene ich habe ist:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = {InboxCoreApplication.class, TestConfig.class}) 
public class InboxServiceTest { 
    @Autowired 
    CouchbaseServiceTestImpl couchBaseServiceTestImpl; 

Wo TestConfig ist:

@Configuration 
public class TestConfig { 
    CouchbaseServiceTestImpl couchbaseServiceTestImpl = new CouchbaseServiceTestImpl(); 

    public CouchbaseService couchbaseService() { 
     return couchbaseServiceTestImpl; 
    } 
} 

Aber jedes Mal, entweder es beschwert sich über dupliziert Bohne (bc es beide Implementierungen sieht), oder es spritzt 2 verschiedene Instanzen des Test Implementierung, eine in der Testklasse und eine im eigentlichen Programm (wat?).

Irgendwelche Vorschläge?

+0

können Sie den Stack-Trace hier hinzufügen? –

+0

Macht Sinn, Sie haben sowohl CouchbaseServiceTestImpl als auch CouchbaseServiceImpl, die beide vom Spring-Container für Ihren Test geladen werden. Einer wird aufgrund 'TestConfig' geladen, der andere aufgrund des Importierens der' InboxCoreApplication', die automatisch eine Komponentensuche für jedes Unterpaket durchführt. – g00glen00b

Antwort

1

Ich denke, ich habe es gefunden.

Es soll an Benutzerprofile:

@Repository 
@Profile("application") 
public class CouchbaseServiceImpl implements CouchbaseService { 

und

@Repository 
@Profile("test") 
public class CouchbaseServiceTestImpl implements CouchbaseService { 

und ich einfach in meinem Test:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = {InboxCoreApplication.class}) 
@ActiveProfiles("test") 
public class InboxObjectRepositoryImplTest { 
1

Ich denke, dein Problem ist mit der folgenden Klasse. Warum implementierst du die CouchbaseService-Schnittstelle neu und machst sie als Testversion? Was ist der wahre Sinn dafür? Ihre Unit-Testklasse sollte entwickelt werden, um die Funktionalität Ihrer Hauptquelle zu testen. Sie erstellen eine Testversion dieser Quellklasse und erstellen einen Komponententest zum Testen dieser Testversion. Was ist der Sinn, das zu tun?

@Repository 
public class CouchbaseServiceTestImpl implements CouchbaseService { 

Also die bessere Implementierung sollte sein, entfernen Sie die CouchbaseServiceTestImpl-Klasse. Schreibe den Komponententest, um das CouchbaseServiceImpl direkt zu testen. (Sie können auch die TestConfig Klasse entfernen)

so sollte der Code so sein.

Der wahre Grund hinter dem Beschweren über die doppelte Bohne kann wie folgt beschrieben werden.

Wenn Sie eine Klasse mit @Repository, @Component oder @Service annotieren, werden diese Klassen vom Spring-IOC-Container automatisch instanziiert und dann im Anwendungskontext registriert, wenn der Spring-Anwendungskontext geladen wird.

Sie haben also zwei Implementierung der CouchbaseService-Schnittstelle. 1. CouchbaseServiceImpl 2. CouchbaseServiceTestImpl

da diese beiden Klassen mit @Repository mit Anmerkungen versehen sind, wird die Feder Applikationsbehälter beide Klassen instanziiert und werden diese beiden Objekte in der IOC-Container halten. Diese beiden Instanzen können der CouchbaseService-Schnittstellenreferenz zugewiesen werden.

schauen Sie sich die folgende Zeile in Ihrem Code an.

@Autowired 
    private CouchbaseService couchbaseService; 

Nun ist der Feder Applikationsbehälter ist in einer zweifelhaften Situation der entsprechende passende Bohne, um herauszufinden, (ob es CouchbaseServiceImpl oder CouchbaseServiceTestImpl verwenden soll. Beide der Bohnen für die Zuordnung in Frage kommen). Deshalb warnt es vor dem Duplikat und macht den Auftrag nicht.

Sie haben zwei Möglichkeiten.

Option 01.

die @Repository Anmerkung in einer dieser Klassen entfernen. vorzugsweise entferne es in CouchbaseServiceTestImpl. (Besser, diese Klasse zu entfernen, wie ich früher erklärt haben)

Option 02

halten alle Klassen, wie man wollte. Benutzer @Qualifier, um dem Spring-Anwendungscontainer über die echte übereinstimmende Bean für die Zuweisung zu informieren.

so sollte der Code wie folgt geändert werden.

@Repository("couchbaseServiceTestImpl") 
public class CouchbaseServiceTestImpl implements CouchbaseService { 

@Repository("couchbaseServiceImpl") 
public class CouchbaseServiceImpl implements CouchbaseService { 

@Repository 
public class InboxObjectRepositoryImpl { 

    @Autowired 
    @Qualifier("couchbaseServiceTestImpl") 
    private CouchbaseService couchbaseService; 

So wird es eine Instanz von CouchbaseServiceTestImpl zu CouchbaseService Referenz zuzuweisen.

+1

Der Grund dafür ist, dass ich das nicht getestet habe. Das ist ein DB-Verbindungsobjekt. Wenn ich den Rest der Anwendung teste, die ich nicht mit einer DB verbinden will, benutze einfach einen In-Memory-Mock. Aber ich sehe Ihre Punkte –

+1

Das hilft mir zwar nicht, weil die anderen Klassen, in die die Bean injiziert wird, nicht in der Lage sein werden, dies zu verwenden, da sie die nicht testgenannte Version verwenden: –

Verwandte Themen