Reputation: 2687
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() {
...
}
}
Upvotes: 8
Views: 11074
Reputation: 201
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
Upvotes: 5
Reputation: 59086
This will be supported in a future Spring Framework version with MockRestServiceServer
; see SPR-15286
Upvotes: 1