From 914b56733fa8bc671107808b97ee7175a4053dc3 Mon Sep 17 00:00:00 2001 From: Kai Moritz Date: Sat, 11 Jan 2020 22:00:41 +0100 Subject: [PATCH] Implemented a WebClientStub to simplify the unit-test --- .../juplo/demo/RemoteContentServiceTest.java | 71 +-- .../java/de/juplo/demo/WebClientStub.java | 449 ++++++++++++++++++ 2 files changed, 451 insertions(+), 69 deletions(-) create mode 100644 src/test/java/de/juplo/demo/WebClientStub.java diff --git a/src/test/java/de/juplo/demo/RemoteContentServiceTest.java b/src/test/java/de/juplo/demo/RemoteContentServiceTest.java index ac1488e..a396d6c 100644 --- a/src/test/java/de/juplo/demo/RemoteContentServiceTest.java +++ b/src/test/java/de/juplo/demo/RemoteContentServiceTest.java @@ -1,27 +1,11 @@ package de.juplo.demo; -import java.net.URI; -import java.nio.charset.Charset; -import java.time.ZonedDateTime; -import java.util.Map; -import java.util.function.Consumer; -import java.util.function.Function; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.web.reactive.function.client.ClientResponse; -import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.reactive.function.client.WebClient.RequestBodyUriSpec; -import org.springframework.web.reactive.function.client.WebClient.RequestHeadersUriSpec; -import org.springframework.web.reactive.function.client.WebClient.ResponseSpec; import reactor.core.publisher.Mono; @@ -34,22 +18,11 @@ public class RemoteContentServiceTest { RemoteContentService service; - @MockBean - WebClient webClient; - @MockBean - RequestHeadersUriSpec headersSpec; - @MockBean - RequestBodyUriSpec bodySpec; - @MockBean - ResponseSpec responseSpec; - @MockBean - ClientResponse clientResponse; - @BeforeEach void setUp() { - service = new RemoteContentService(webClient); + service = new RemoteContentService(WebClientStub.WEB_CLIENT); } @@ -57,47 +30,7 @@ public class RemoteContentServiceTest void test() { Mono mono = Mono.just("bar"); - - when(webClient.options()).thenReturn(headersSpec); - when(webClient.head()).thenReturn(headersSpec); - when(webClient.get()).thenReturn(headersSpec); - when(webClient.method(any(HttpMethod.class))).thenReturn(bodySpec); - when(headersSpec.uri(any(URI.class))).thenReturn(headersSpec); - when(headersSpec.uri(any(String.class), any(Function.class))).thenReturn(headersSpec); - when(headersSpec.uri(any(String.class), any(Map.class))).thenReturn(headersSpec); - when(headersSpec.uri(any(String.class), (Object[])any())).thenReturn(headersSpec); - when(headersSpec.uri(any(Function.class))).thenReturn(headersSpec); - when(headersSpec.accept((MediaType[])any())).thenReturn(headersSpec); - when(headersSpec.acceptCharset((Charset[])any())).thenReturn(headersSpec); - when(headersSpec.attribute(any(String.class), any(Object.class))).thenReturn(headersSpec); - when(headersSpec.cookie(any(String.class), any(String.class))).thenReturn(headersSpec); - when(headersSpec.cookies(any(Consumer.class))).thenReturn(headersSpec); - when(headersSpec.exchange()).thenReturn(mono); - when(headersSpec.header(any(String.class), (String[])any())).thenReturn(headersSpec); - when(headersSpec.headers(any(Consumer.class))).thenReturn(headersSpec); - when(headersSpec.ifModifiedSince(any(ZonedDateTime.class))).thenReturn(headersSpec); - when(headersSpec.ifNoneMatch((String[])any())).thenReturn(headersSpec); - when(headersSpec.retrieve()).thenReturn(responseSpec); - when(bodySpec.uri(any(URI.class))).thenReturn(bodySpec); - when(bodySpec.uri(any(String.class), any(Function.class))).thenReturn(bodySpec); - when(bodySpec.uri(any(String.class), any(Map.class))).thenReturn(bodySpec); - when(bodySpec.uri(any(String.class), (Object[])any())).thenReturn(bodySpec); - when(bodySpec.uri(any(Function.class))).thenReturn(bodySpec); - when(bodySpec.accept((MediaType[])any())).thenReturn(bodySpec); - when(bodySpec.acceptCharset((Charset[])any())).thenReturn(bodySpec); - when(bodySpec.attribute(any(String.class), any(Object.class))).thenReturn(bodySpec); - when(bodySpec.cookie(any(String.class), any(String.class))).thenReturn(bodySpec); - when(bodySpec.cookies(any(Consumer.class))).thenReturn(bodySpec); - when(bodySpec.exchange()).thenReturn(Mono.just(clientResponse)); - when(bodySpec.header(any(String.class), (String[])any())).thenReturn(bodySpec); - when(bodySpec.headers(any(Consumer.class))).thenReturn(bodySpec); - when(bodySpec.ifModifiedSince(any(ZonedDateTime.class))).thenReturn(bodySpec); - when(bodySpec.ifNoneMatch((String[])any())).thenReturn(bodySpec); - when(bodySpec.contentLength(any(Long.class))).thenReturn(bodySpec); - when(bodySpec.contentType(any(MediaType.class))).thenReturn(bodySpec); - when(bodySpec.retrieve()).thenReturn(responseSpec); - when(responseSpec.bodyToMono(String.class)).thenReturn(mono); - when(clientResponse.bodyToMono(String.class)).thenReturn(mono); + WebClientStub.expect(mono); Mono result = service.getRemoteText("/foo"); diff --git a/src/test/java/de/juplo/demo/WebClientStub.java b/src/test/java/de/juplo/demo/WebClientStub.java new file mode 100644 index 0000000..328029c --- /dev/null +++ b/src/test/java/de/juplo/demo/WebClientStub.java @@ -0,0 +1,449 @@ +package de.juplo.demo; + + +import java.net.URI; +import java.nio.charset.Charset; +import java.time.ZonedDateTime; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.IntPredicate; +import java.util.function.Predicate; +import java.util.function.Supplier; +import org.reactivestreams.Publisher; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.reactive.ClientHttpRequest; +import org.springframework.util.MultiValueMap; +import org.springframework.web.reactive.function.BodyInserter; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.util.UriBuilder; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + + +/** + * A stub for {@link WebClient}, that can be used for mocking. + * @author Kai Moritz + */ +public class WebClientStub implements WebClient +{ + public final static WebClientStub WEB_CLIENT = new WebClientStub(); + public final static RequestHeadersUriSpecStub HEADERS_SPEC = new RequestHeadersUriSpecStub(); + public final static RequestBodySpecStub REQUEST_BODY_SPEC = new RequestBodySpecStub(); + public final static ResponseSpecStub RESPONSE_SPEC = new ResponseSpecStub(); + + private static Supplier> TO_MONO = () -> null; + private static Supplier> TO_FLUX = () -> null; + + + public static void expect(Mono mono) { TO_MONO = () -> mono; } + public static void expect(Flux flux) { TO_FLUX = () -> flux; } + + + private WebClientStub() {} + + + @Override + public WebClient.RequestHeadersUriSpec get() + { + return HEADERS_SPEC; + } + + @Override + public WebClient.RequestHeadersUriSpec head() + { + return HEADERS_SPEC; + } + + @Override + public WebClient.RequestBodyUriSpec post() + { + return REQUEST_BODY_SPEC; + } + + @Override + public WebClient.RequestBodyUriSpec put() + { + return REQUEST_BODY_SPEC; + } + + @Override + public WebClient.RequestBodyUriSpec patch() + { + return REQUEST_BODY_SPEC; + } + + @Override + public WebClient.RequestHeadersUriSpec delete() + { + return HEADERS_SPEC; + } + + @Override + public WebClient.RequestHeadersUriSpec options() + { + return HEADERS_SPEC; + } + + @Override + public WebClient.RequestBodyUriSpec method(HttpMethod hm) + { + return REQUEST_BODY_SPEC; + } + + @Override + public WebClient.Builder mutate() + { + throw new UnsupportedOperationException("Stub is immutable!"); + } + + + public static class RequestHeadersUriSpecStub implements WebClient.RequestHeadersUriSpec + { + private RequestHeadersUriSpecStub() {} + + + @Override + public WebClient.RequestHeadersSpec uri(URI uri) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec uri(String string, Object... os) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec uri(String string, Map map) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec uri(String string, Function fnctn) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec uri(Function fnctn) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec accept(MediaType... mts) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec acceptCharset(Charset... chrsts) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec cookie(String string, String string1) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec cookies(Consumer cnsmr) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec ifModifiedSince(ZonedDateTime zdt) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec ifNoneMatch(String... strings) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec header(String string, String... strings) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec headers(Consumer cnsmr) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec attribute(String string, Object o) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec attributes(Consumer cnsmr) + { + return this; + } + + @Override + public WebClient.ResponseSpec retrieve() + { + return RESPONSE_SPEC; + } + + @Override + public Mono exchange() + { + return WebClientStub.TO_MONO.get(); + } + } + + public static class RequestBodySpecStub implements WebClient.RequestBodyUriSpec + { + private RequestBodySpecStub() {} + + + @Override + public WebClient.RequestBodySpec contentLength(long l) + { + return this; + } + + @Override + public WebClient.RequestBodySpec contentType(MediaType mt) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec bodyValue(Object o) + { + return this; + } + + @Override + public > WebClient.RequestHeadersSpec body(P p, Class type) + { + return this; + } + + @Override + public > WebClient.RequestHeadersSpec body(P p, ParameterizedTypeReference ptr) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec body(Object o, Class type) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec body(Object o, ParameterizedTypeReference ptr) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec body( BodyInserter bi) + { + return this; + } + + @Override + public WebClient.RequestHeadersSpec syncBody(Object o) + { + return this; + } + + @Override + public WebClient.RequestBodySpec accept(MediaType... mts) + { + return this; + } + + @Override + public WebClient.RequestBodySpec acceptCharset(Charset... chrsts) + { + return this; + } + + @Override + public WebClient.RequestBodySpec cookie(String string, String string1) + { + return this; + } + + @Override + public WebClient.RequestBodySpec cookies(Consumer> cnsmr) + { + return this; + } + + @Override + public WebClient.RequestBodySpec ifModifiedSince(ZonedDateTime zdt) + { + return this; + } + + @Override + public WebClient.RequestBodySpec ifNoneMatch(String... strings) + { + return this; + } + + @Override + public WebClient.RequestBodySpec header(String string, String... strings) + { + return this; + } + + @Override + public WebClient.RequestBodySpec headers(Consumer cnsmr) + { + return this; + } + + @Override + public WebClient.RequestBodySpec attribute(String string, Object o) + { + return this; + } + + @Override + public WebClient.RequestBodySpec attributes(Consumer> cnsmr) + { + return this; + } + + @Override + public WebClient.ResponseSpec retrieve() + { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Mono exchange() + { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public WebClient.RequestBodySpec uri(URI uri) + { + return this; + } + + @Override + public WebClient.RequestBodySpec uri(String string, Object... os) + { + return this; + } + + @Override + public WebClient.RequestBodySpec uri(String string, Map map) + { + return this; + } + + @Override + public WebClient.RequestBodySpec uri(String string, Function fnctn) + { + return this; + } + + @Override + public WebClient.RequestBodySpec uri(Function fnctn) + { + return this; + } + } + + public static class ResponseSpecStub implements WebClient.ResponseSpec + { + private ResponseSpecStub() {} + + + @Override + public WebClient.ResponseSpec onStatus(Predicate statusPredicate, Function> exceptionFunction) + { + return this; + } + + @Override + public WebClient.ResponseSpec onRawStatus(IntPredicate statusCodePredicate, Function> exceptionFunction) + { + return this; + } + + @Override + public Mono bodyToMono(Class elementClass) + { + return (Mono)TO_MONO.get(); + } + + @Override + public Mono bodyToMono(ParameterizedTypeReference elementTypeRef) + { + return (Mono)TO_MONO.get(); + } + + @Override + public Flux bodyToFlux(Class elementClass) + { + return (Flux)TO_FLUX; + } + + @Override + public Flux bodyToFlux(ParameterizedTypeReference elementTypeRef) + { + return (Flux)TO_FLUX; + } + + @Override + public Mono> toEntity(Class bodyClass) + { + return (Mono>)TO_MONO.get(); + } + + @Override + public Mono> toEntity(ParameterizedTypeReference bodyTypeReference) + { + return (Mono>)TO_MONO.get(); + } + + @Override + public Mono>> toEntityList(Class elementClass) + { + return (Mono>>)TO_MONO.get(); + } + + @Override + public Mono>> toEntityList(ParameterizedTypeReference elementTypeRef) + { + return (Mono>>)TO_MONO.get(); + } + + @Override + public Mono> toBodilessEntity() + { + return (Mono>)TO_MONO.get(); + } + } +} -- 2.20.1