I need to unit test a class that uses the WebClient
. Is there any good way to deal with the WebClient?
With the RestTemplate
I could easily use Mockito. Mocking the WebClient is a bit tedious, since deep stubs don't work with the webclient...
I want to test if my code provides the correct headers... shortened sample code:
public class MyOperations {
private final WebClient webClient;
public MyOperations(WebClient webClient) {
this.webClient = webClient;
}
public Mono<ResponseEntity<String>> get( URI uri) {
return webClient.get()
.uri(uri)
.headers(computeHeaders())
.accept(MediaType.APPLICATION_JSON)
.retrieve().toEntity(String.class);
}
private HttpHeaders computeHeaders() {
...
}
}
We have two main options for mocking in our tests: Use Mockito to mimic the behavior of WebClient. Use WebClient for real, but mock the service it calls by using MockWebServer (okhttp)
This is aimed to unit, not integration tests...
Implemented in Kotlin, this is a bit rudimentary, but it's effective. The idea can be extracted from this pieces of code below
First, a WebClient kotlin extension
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mockito.*
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.reactive.function.client.WebClientResponseException
import reactor.core.publisher.toMono
fun WebClient.mockAndReturn(data: Any) {
val uriSpec = mock(WebClient.RequestBodyUriSpec::class.java)
doReturn(uriSpec).`when`(this).get()
doReturn(uriSpec).`when`(this).post()
...
val headerSpec = mock(WebClient.RequestBodyUriSpec::class.java)
doReturn(headerSpec).`when`(uriSpec).uri(anyString())
doReturn(headerSpec).`when`(uriSpec).uri(anyString(), anyString())
doReturn(headerSpec).`when`(uriSpec).uri(anyString(), any())
doReturn(headerSpec).`when`(headerSpec).accept(any())
doReturn(headerSpec).`when`(headerSpec).header(any(), any())
doReturn(headerSpec).`when`(headerSpec).contentType(any())
doReturn(headerSpec).`when`(headerSpec).body(any())
val clientResponse = mock(WebClient.ResponseSpec::class.java)
doReturn(clientResponse).`when`(headerSpec).retrieve()
doReturn(data.toMono()).`when`(clientResponse).bodyToMono(data.javaClass)
}
fun WebClient.mockAndThrow() {
doThrow(WebClientResponseException::class.java).`when`(this).get()
doThrow(WebClientResponseException::class.java).`when`(this).post()
...
}
Then, the unit test
class MyRepositoryTest {
lateinit var client: WebClient
lateinit var repository: MyRepository
@BeforeEach
fun setUp() {
client = mock(WebClient::class.java)
repository = MyRepository(client)
}
@Test
fun getError() {
assertThrows(WebClientResponseException::class.java, {
client.mockAndThrow()
repository.get("x")
})
}
@Test
fun get() {
val myType = MyType()
client.mockAndReturn(myType)
assertEquals(myType, repository.get("x").block())
}
}
Note: tests on JUnit 5
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With