Diciamo che sto scrivendo i test di integrazione Spring per un servizio REST A. Questo servizio a sua volta colpisce un altro servizio REST B e ottiene un elenco di URI da colpire su REST servizio C. È una specie di modello di auto-scoperta. Voglio prendere in giro le risposte B e C usando MockRestServiceServer.
Ora la risposta da B è un elenco di URI, sono tutti molto simili, e per il bene di questo esempio consente di dire la mia risposta da B è in questo modo:Spring MockRestServiceServer che gestisce più richieste allo stesso URI (rilevamento automatico)
{
uris: ["/stuff/1.json", "/stuff/2.json", "/stuff/39.json", "/stuff/47.json"]
}
Semplicemente servizio à aggiungerà ciascuno di loro sull'URL di base per il servizio C e fanno quelle richieste.
Mocking B è facile poiché è solo una richiesta.
Mocking C è una seccatura come avrei dovuto prendere in giro ogni singolo URI per appropriarsi della risposta simulata. Voglio automatizzarlo!
Quindi, prima ho scrivere il mio matcher a non corrisponde un URL completo, ma parte di esso:
public class RequestContainsUriMatcher implements RequestMatcher {
private final String uri;
public RequestContainsUriMatcher(String uri){
this.uri = uri;
}
@Override
public void match(ClientHttpRequest clientHttpRequest) throws IOException, AssertionError {
assertTrue(clientHttpRequest.getURI().contains(uri));
}
}
Questo funziona bene come ora posso fare questo:
public RequestMatcher requestContainsUri(String uri) {
return new RequestContainsUriMatcher(uri);
}
MockRestServiceServer.createServer(restTemplate)
.expect(requestContainsUri("/stuff"))
.andExpect(method(HttpMethod.GET))
.andRespond(/* I will get to response creator */);
Ora ho solo bisogno di un creatore risposta che conosce l'URL richiesta completa e dove i dati finto siede (avrò come file JSON nella cartella risorse di test):
public class AutoDiscoveryCannedDataResponseCreator implements ResponseCreator {
private final Function<String, String> cannedDataBuilder;
public AutoDiscoveryCannedDataResponseCreator(Function<String, String> cannedDataBuilder) {
this.cannedDataBuilder = cannedDataBuilder;
}
@Override
public ClientHttpResponse createResponse(ClientHttpRequest clientHttpRequest) throws IOException {
return withSuccess(cannedDataBuilder.apply(requestUri), MediaType.APPLICATION_JSON)
.createResponse(clientHttpRequest);
}
}
Ora roba è facile, ho HAV e per scrivere un costruttore che prende l'URI di richiesta come una stringa e restituisce dati falsi, come una stringa! Brillante!
public ResponseCreator withAutoDetectedCannedData() {
Function<String, String> cannedDataBuilder = new Function<String, String>() {
@Override
public String apply(String requestUri) {
//logic to get the canned data based on URI
return cannedData;
}
};
return new AutoDiscoveryCannedDataResponseCreator(cannedDataBuilder);
}
MockRestServiceServer.createServer(restTemplate)
.expect(requestContainsUri("/stuff"))
.andExpect(method(HttpMethod.GET))
.andRespond(withAutoDetectedCannedData());
funziona benissimo! .... Per la prima richiesta.
Dopo la prima richiesta (/stuff/1.json) il mio MockRestServiceServer risponde con il messaggio "Errore asserzione: non sono previste ulteriori richieste".
Fondamentalmente, posso fare tutte le richieste a quel MockRestServiceServer quante erano le chiamate .expect() su di esso. E dal momento che ne avevo solo 1, solo la prima richiesta passerà.
C'è un modo per aggirarlo? Davvero non voglio prendere in giro il servizio C 10 o 20 volte ...
Grazie per l'attuazione RequestContainsUriMatcher – Silentbang