Here is a working example:

@Component
public class QuotesClient {

  private final WebClient webClient;

  public QuotesClient(WebClient.Builder builder, @Value("${client.baseUrl}") String baseUrl) {
    this.webClient = builder.baseUrl(baseUrl).build();
  }

  public JsonNode getData() {
    return this.webClient
      .get()
      .retrieve()
      .bodyToMono(JsonNode.class)
      .block();
  }
}

Using the WebClient.Builder is optional.

The corresponding test can look like the following:

class QuotesClientTest {

  private QuotesClient quotesClient;
  private MockWebServer server;

  @BeforeEach
  public void setup() {
    this.server = new MockWebServer();
    this.quotesClient = new QuotesClient(WebClient.builder(), server.url("/").toString());
  }

  @Test
  public void test() {

    server.enqueue(new MockResponse()
      .setStatus("HTTP/1.1 200")
      .setBody("{\"bar\":\"barbar\",\"foo\":\"foofoo\"}")
      .addHeader("Content-Type", "application/json"));

    JsonNode data = quotesClient.getData();
    assertNotNull(data);

    System.out.println(data);

  }

}

If you are searching for a similar setup using WireMock, Spring Boot, and JUnit 5, take a look at the linked guide.

Answer from rieckpil on Stack Overflow
🌐
rieckpil
rieckpil.de › home › spring framework tutorials › test spring webclient with mockwebserver from okhttp
Test Spring WebClient with MockWebServer from OkHttp - rieckpil
August 27, 2021 - It seems there won’t be an integration with the MockRestServiceServer for the WebClient. The recommended way is to use MockWebServer from OkHttp. With this blog post, you’ll learn how to use the MockWebServer to test parts of your application using the Spring WebClient. Our sample project is a basic Spring Boot application.
🌐
Bobsantosjr
bobsantosjr.com › springboot-spock-mockwebserver
Using MockWebServer with Spring Boot and Spock - Bob Santos Jr.
We can use MockWebServer as is or we can use a library from fabric8 that wraps MockWebServer and gives us a nice DSL. Or do as I’ve done and create our own simple wrapper around MockWebServer. We will be using Spring Boot and Spock for this example. We’ll be using RestTemplate to call external ...
🌐
Spring
docs.spring.io › spring-framework › reference › web › webflux-webclient › client-testing.html
Testing :: Spring Framework
To test code that uses the WebClient, you can use a mock web server, such as OkHttp MockWebServer or WireMock.
🌐
Shouldn't Be Hard
arhohuttunen.com › spring-boot-webclient-mockwebserver
Testing Spring Boot WebClient With MockWebServer | Shouldn't Be Hard
May 22, 2021 - A better approach is to use a fake server like MockWebServer and let the web client make requests against that. To mock the WebClient in other tests, we can first write a wrapper class for it and then mock that instead. We can integration test the web client separately, and other tests don’t have to worry about the web client. You can find the example code for this article on Codeberg. This article is part of the Spring Boot ...
🌐
Industrial Logic
industriallogic.com › blog › better-integration-testing-with-mockwebserver
Better Integration Testing with MockWebServer
April 13, 2022 - I had previously written an article Integration Testing with MockWebServer that explained a way to write integration tests for a web application using WebClient and MockWebServer (okhttp). The intention was to write an integration test that did not touch the inside of the code, but only the edges. It was not completely successful. The tests overrode the WebClient, and so did not cover the configuration of the WebClient (which could be incorrectly configured). Spring Boot 2.2.6 introduced the @DynamicPropertySource which allows you to insert the MockWebServer url into the properties at runtime.
🌐
Baeldung
baeldung.com › home › spring › mocking a webclient in spring
Mocking a WebClient in Spring | Baeldung
January 8, 2024 - While Mockito worked, and may be a good option for simple examples, the recommended approach is to use MockWebServer.
🌐
Medium
jskim1991.medium.com › spring-boot-using-mockwebserver-for-integration-tests-499030f6bfff
[Spring Boot] Using WireMock and MockWebServer for Spring WebFlux Integration Tests | by Jay Kim | Medium
August 8, 2023 - For setting up MockWebServer, a couple of dependencies need to be added. // plugins, group, version, java, repositories dependencies { implementation("org.springframework.boot:spring-boot-starter-actuator") implementation("org.springframework.boot:spring-boot-starter-webflux") testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("io.projectreactor:reactor-test") testImplementation("com.squareup.okhttp3:okhttp") testImplementation("com.squareup.okhttp3:mockwebserver") }
Find elsewhere
🌐
Mimacom
blog.mimacom.com › spring-webclient-testing
Testing Spring WebClient with MockWebServer | mimacom
October 16, 2020 - This is well documented in the Spring Boot Reference Documentation. Unfortunately the RestClientTest only supports RestTemplate, but not WebClient and thus cannot be used in a reactive Spring WebFlux application. The recommended alternative for WebFlux is the use of a mock web server provided by the OkHttp library. The setup is only slightly more complex than before: // Testing with Spring WebFlux and WebClient class TodoServiceTest { private static MockWebServer mockWebServer; private static TodoService todoService; @BeforeAll static void beforeAll() { mockWebServer = new MockWebServer(); tod
🌐
Medium
medium.com › @swarts_uk › testing-spring-boot-webclient-with-mockwebserver-815478f5b484
Testing Spring Boot WebClient with MockWebServer | by Swarts UK | Medium
April 17, 2021 - When a service needs to request some information from another service over HTTP, Spring offers WebClient as the new reactive asynchronous HTTP client with a fluent functional style API. In this post, we will look at how to use WebClient to make a call to a 3rd party API and test it. Instead of calling the API itself we will mock it with a MockWebServer which is a lightweight web server that can receive and respond to HTTP requests.
🌐
Industrial Logic
industriallogic.com › blog › integration-testing-with-mockwebserver
Integration Testing with MockWebServer
February 15, 2021 - To test how your application handles 500 responses, mock the server to return a 500 response and assert on what you want your response to that error to be. For an example of a 500 test case, see my GitHub repo here. Mockrestserviceserver Mockwebserver Spring Webflux Flux Integration Mock ...
Top answer
1 of 4
23

Since Spring Framework 5.2.5 (Spring Boot 2.x) you can use DynamicPropertySource annotation which is quite handy.

Here is a complete example how you can use it with MockWebServer to bind the correct port:

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public abstract class AbstractIT {

    static MockWebServer mockWebServer;

    @DynamicPropertySource
    static void properties(DynamicPropertyRegistry r) throws IOException {
        r.add("some-service.url", () -> "http://localhost:" + mockWebServer.getPort());
    }

    @BeforeAll
    static void beforeAll() throws IOException {
        mockWebServer = new MockWebServer();
        mockWebServer.start();
    }

    @AfterAll
    static void afterAll() throws IOException {
        mockWebServer.shutdown();
    }
}
2 of 4
3

Here's a solution that's working from me. Spring Boot 2 & Spring-Webflux 5.3.30 using SpringBootTest

  1. MyServiceClientTestConfig creates injected beans port and myServiceClient, where

    • The port Integer bean is generated using Spring's TestSocketUtils.findAvailableTcpPort()
    • MyServiceClient is a Spring service that uses WebClient and gets initialized with a base URL.
  2. As documented we should not re-use a MockWebServer instance between tests so create it before each test using the port we found free at test initialization and shut it down after each test.

I suppose there is a slim chance that since I find the port once when Spring is initializing the application context and there are short periods of time where it is not in use by MockWebServer, before the first call to init and between tests, that another process could take the port but the odds of that happening during the lifetime of the test seem incredibly small.

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class MyServiceClientTest {

    private static final Logger LOG = LoggerFactory.getLogger(MyServiceClientTest.class);

    private MockWebServer mockWebServer;

    @Autowired
    private MyServiceClient myServiceClient;

    @Autowired
    private Integer port;

    @BeforeEach
    void init() throws IOException {
        assertNotNull(myServiceClient);
        assertNotNull(port);

        // MockWebServer not re-usable between tests
        mockWebServer = new MockWebServer();
        mockWebServer.start(port);

        assertNotNull(mockWebServer);
        assertEquals(port, mockWebServer.getPort());
    }

    @AfterEach
    void cleanUp() throws IOException {
        // MockWebServer not re-usable between tests
        mockWebServer.shutdown();
    }

    @Test
    public void placeholderTest1() {
        LOG.info("Hello 1 {}", mockWebServer.getPort());
    }

    @Test
    public void placeholderTest2() {
        LOG.info("Hello 2 {}", mockWebServer.getPort());
    }

    @Configuration
    static class MyServiceClientTestConfig {

        @Bean
        Integer getFreePort () {
            // find a free port to use for this test
            return TestSocketUtils.findAvailableTcpPort();
        }

        @Bean
        MyServiceClient getMyServiceClient(Integer port) {
            return new MyServiceClient(String.format("http://localhost:%d", port));
        }
    }
}
🌐
Spring
docs.spring.io › spring-framework › reference › testing › spring-mvc-test-client.html
Testing Client Applications :: Spring Framework
To test code that uses the RestClient or RestTemplate, you can use a mock web server, such as OkHttp MockWebServer or WireMock.
🌐
Stack Overflow
stackoverflow.com › questions › 72358534 › unit-testing-on-springboot-webclient-with-mockwebserver
spring boot - Unit Testing on Springboot WebClient with MockWebServer - Stack Overflow
May 24, 2022 - @ExtendWith(MockitoExtension::class) @MockitoSettings(strictname = Strictness.LENIENT) @TestInstance(TestInstance.Lifecycle.PER_CLASS) class ApiServiceTest { @Mock private lateinit var webClient: WebClient @InjectMocks private lateinit var mockApiService: ApiService private val mockName = "mockName" private val mockDetailDto = DetailDto(name = "mockName", age = 18) @Test fun canGetDetails() { mockWebServer.enqueue( MockResponse() .setResponse(200) .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .setBody(mockDetailDto)) ) mockApiService.getApiResult(mockName) val request: RecordedRequest = mockWebServer.takeRequest() // Assert statements with request } }
🌐
GitHub
github.com › spring-projects › spring-boot › issues › 14223
Provide MockWebServer Integration · Issue #14223 · spring-projects/spring-boot
August 28, 2018 - spring.security.oauth2.resourceserver.jwt.issuer-uri=${mockwebserver.url}/oauth2/keys · Spring Boot could provide a hook that would change ${mockwebserver.url} into a URL created using MockWebServer.url.
Author: spring-projects
🌐
GitHub
github.com › rwinch › spring-webclient-sample › blob › master › src › test › java › sample › WebClientTests.java
spring-webclient-sample/src/test/java/sample/WebClientTests.java at master · rwinch/spring-webclient-sample
import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication; · /** * @author Rob Winch · * @since 5.0 · */ public class WebClientTests { · private MockWebServer server; · private WebClient webClient; ·
Author: rwinch
🌐
Jamie Tanna
jvt.me › posts › 2022 › 02 › 07 › webclient-integration-test
Integration Testing Your Spring `WebClient`s with okhttp's `MockWebServer` · Jamie Tanna | Software Engineer
February 7, 2022 - A common choice for this is Wiremock or MockServer, and I'd hoped to say that, similar to integration testing our RestTemplates, we'd be able to use Spring Boot's RestClientTest, but there's no plan for Spring Boot to have this functionality. We can, however, use okhttp3's MockWebServer as noted on the issue above, and in this blog by Mimacom, which may be slightly more lightweight than our other options.