2015-12-21 19 views
7

Ich verwende Federwolke Eureka und vortäuschen, um zwischen einigen Diensten zu kommunizieren (sagen wir A und B). Jetzt möchte ich meine Service-Schicht eines einzelnen Dienstes (A) unittest. Das Problem ist, dass dieser Dienst (A) einen Schein-Client verwendet, um einige Informationen des anderen Dienstes (B) anzufordern.Mock ein Eureka Feign Client für Unittesting

Das Ausführen der Unittests ohne spezielle Konfiguration löst die folgende Ausnahme aus: java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: service-b => aber ich möchte keinen Server ausführen.

Meine Frage ist: Gibt es eine Möglichkeit, den Schein-Client zu verspotten, so kann ich meinen Dienst (A) unittest ohne eine Eureka-Instanz und Dienst (B) zu betreiben?

Edit: Ich endete damit, einen Stub für den Schein Client zu erstellen. Der Stub wird als eine primäre Komponente markiert, um die Feder zu zwingen, den Stub innerhalb meiner Tests zu instantiieren.
Dies ist die Lösung, die ich mir ausgedacht habe.

//the feign client 
@FeignClient("user") 
public interface UserClient { 
    UserEntity getUser(); 
} 

//the implementation i use for the tests 
@Component 
@Primary //mark as primary implementation 
public class UserClientTestImpl implements UserClient { 
    @Override public UserEntity getUser() { 
     return someKindOfUser; 
    } 
} 

Antwort

4

Die Frage ist ... müssen Sie sogar spotten? Ich sehe oft, dass Leute "Mock" als erste Lösung für alles nennen, was "nicht Teil des Komponententests sein sollte". Spott ist eine Technik, nicht die Lösung für alles. (siehe).

Wenn Sie sich noch in den frühen Phasen Ihres Codes befinden, refactorieren Sie und verwenden Sie etwas anderes, anstatt von der konkreten Instanz des Feign Clients abhängig zu sein. Sie können eine Schnittstelle, eine abstrakte Klasse, eine Eigenschaft oder was auch immer Sie wollen verwenden. Verlassen Sie sich nicht auf das Objekt selbst, sonst müssen Sie es "verspotten".

public interface IWebClient { 
    public String get(...); 
    public String post(...); 
} 

Auf die Frage, aber ich will anderen Code haben, der das gleiche genau tun wird (außer, dass es auf die konkrete Instanz Feign sein wird), was soll ich tun dann? Nun, Sie können einen Funktionstest schreiben und eine Instanz eines Webservers aufrufen, den Sie lokal einrichten können - oder verwenden Sie Wiremock, wie von Marcin Grzejszczak in einer der Antworten erwähnt.

public class FeignClientWrapper implements IWebClient { 
    private feign = something 

    public String get() { 
    feign.get(...) 
    } 

    public String post() { 
    feign.post(...) 
    } 
} 

Unit-Tests werden verwendet, Algorithmen zu testen, wenn/else, Schleifen: wie Einheiten Arbeit. Schreibe keinen Code, um Mocks fit zu machen - es muss umgekehrt sein: Dein Code sollte weniger Abhängigkeiten haben und du solltest nur dann mocksen, wenn du das Verhalten verifizieren musst (sonst kannst du einen Stub oder ein falsches Objekt verwenden): Müssen Sie das Verhalten überprüfen? Müssen Sie testen, dass eine bestimmte Methode in Ihrem Code aufgerufen wird? Oder dass eine bestimmte Methode dreimal hintereinander mit X, Y und Z aufgerufen wird? Nun, dann ja, Spott ist in Ordnung.

Andernfalls verwenden Sie ein gefälschtes Objekt: Was Sie wollen, ist nur den Anruf/Antwort und vielleicht den Statuscode zu testen. Wahrscheinlich wollen Sie nur testen, wie Ihr Code auf verschiedene Ausgaben reagiert (z. B. das Feld "Fehler" in einer JSON-Antwort) oder unterschiedliche Statuscodes (vorausgesetzt, die Client-Dokumentation stimmt: 200 OK bei GET, 201 wenn POST, usw.).

+0

Dies ist die Lösung, die ich mit so weit kam: Die feign Schnittstelle '@FeignClient ("user") public interface UserClient { // einige feign Anmerkungen UserEntity getUser(); } ' Die Implementierung i für die Tests verwenden ' @Component @Primary public class UserClientTestImpl implementiert UserClient { @Override public UserEntity getUser() { return someKindOfUser; } } ' Grundsätzlich ist es die Methode, die Sie @Markon erwähnt haben. –

+0

Könnten Sie vielleicht den Code in Ihre Frage schreiben? Es ist schwer Code in den Kommentaren zu lesen: D Ich bin froh, dass es geholfen hat. Wenn Sie das Verhalten testen möchten, dann können Sie Spott verwenden. Wenn Sie die "Verbindung" testen möchten, richten Sie einen kleinen Webserver ein! : P – Markon

1

Wenn Sie einen Mock verwenden müssen, können Sie mit Wiremock die Antwort für eine bestimmte Anfrage stubben - http://wiremock.org/stubbing.html. Auf diese Weise werden Integrationstests mit echten HTTP-Anfragen gesendet. Für Unit-Tests ist die Antwort von @Markon sehr gut.

1

Einen Schein-Client zu verspotten ist wirklich nützlich in Microservice Komponententests. Sie möchten einen Microservice testen, ohne alle anderen Microservices starten zu müssen. Wenn du Spring verwendest (und es so aussieht, als ob du es bist), wird die @MockBean-Annotation zusammen mit etwas Mockito-Code funktionieren.

@RunWith(SpringRunner.class) 
@SpringBootTest(webEnvironment = 
SpringBootTest.WebEnvironment.DEFINED_PORT) 
public class TestYourComponent { 
    @Configuration 
    @Import({YourConfiguration.class}) 
    public static class TestConfiguration { 
    } 

    @MockBean 
    private UserClient userClient; 

    @Test 
    public void someTest() 
    { 
     //... 
     mockSomeBehavior(); 
     //... 
    } 

    private void mockSomeBehavior() { 
     Mockito.doReturn(someKindOfUser).when(userClient).getUser(); 
    } 
} 
Verwandte Themen