AdBlock Detected

It looks like you're using an ad-blocker!

Our team work realy hard to produce quality content on this website and we noticed you have ad-blocking enabled. Advertisements and advertising enable us to continue working and provide high-quality content.

MockWebServer with WebClient of Spring

In this article, we are going to delve into how to perform integrated tests using MockWebServer with WebClient of Spring. The use of MockWebServer allows us to mock any request made through our WebClient.

MockWebServer acts as a web server, intercepting the made request and returning a pre-established response body.

Main features of MockWebServer

  1. Testing HTTP Interactions: Spring applications often rely on making HTTP requests to external APIs or services. MockWebServer mocks web server behavior, intercepts HTTP requests, and provides predefined responses for testing different scenarios and HTTP interactions.
  2. Isolation and Deterministic Testing: By using MockWebServer, you can isolate your Spring application from the actual web services it communicates with during testing. This ensures that your tests are not affected by the availability or reliability of those external services. You have control over the responses returned by the MockWebServer, making your tests deterministic and consistent.
  3. Flexible Response Configuration: MockWebServer allows you to configure various aspects of the responses, including response codes, headers, and response bodies. This flexibility enables you to simulate different scenarios and edge cases, such as testing error handling or specific response formats, without relying on the actual external services.
  4. Easy Integration with Spring Testing: You can easily integrate MockWebServer into your Spring tests, whether you use the Spring MVC Test framework or WebClient. We can use MockWebServer alongside other testing frameworks like JUnit or Spock to create comprehensive and reliable tests for your Spring applications involving HTTP interactions.

Overall, MockWebServer provides a convenient and powerful tool for testing the HTTP interactions of your Spring applications, allowing you to create reliable and deterministic tests in a controlled environment.

Using MockWebServer

MockWebServer Dependencies

Let’s add the following dependencies to include the necessary libraries:

    <dependency>
      <groupId>com.squareup.okhttp3</groupId>
      <artifactId>okhttp</artifactId>
      <version>4.5.0</version>
    </dependency>

    <dependency>
      <groupId>com.squareup.okhttp3</groupId>
      <artifactId>mockwebserver</artifactId>
      <version>4.5.0</version>
      <scope>test</scope>
    </dependency>

To use the libraries, we have added both the mockwebserver and okhttp dependencies.

Adding MockWebServer to Our Tests

Let’s add MockWebServer to our tests using Spock:

@SpringBootTest(classes = StratioSpringBootService.class)
@AutoConfigureMockMvc
abstract class ResourceISpec extends Specification {

    @Autowired
    protected MockMvc mockMvc

    static MockWebServer mockBackEnd

    def setupSpec() {
        mockBackEnd = new MockWebServer()
        mockBackEnd.start(37639)
    }

    def cleanSpec() {
        mockBackEnd.shutdown()
    }

}

As we can see in this code snippet, we have added the MockWebServer class, which has been imported as static.

Next, we need to start the MockWebServer before any test is executed, similar to @BeforeAll, by specifying the port where we want to run it. Finally, the last configuration step would be to shut down the MockWebServer when finish our test.

Next, we add a class that extends the previous abstract class to make use of MockWebServer.

class CarWorkshopISpec extends ResourceISpec {

    static final CAR_INFO_PATH = "fixtures/carWorkshop/carInfo.json"

    static final CAR_LOCATION_PATH = "fixtures/carWorkshop/carLocation.json"

    @Shared
    String carInfo

    @Shared
    String carLocation

    def setup() {

        mockBackEnd.setDispatcher(new Dispatcher() {
            @Override
            MockResponse dispatch(@NotNull RecordedRequest recordedRequest) throws InterruptedException {
                if (recordedRequest.getPath().startsWith("/carworkshop/car-info")) {
                    return new MockResponse().setResponseCode(200).setBody(carInfo)
                } else if (recordedRequest.getPath().startsWith("/carworkshop/car-location")) {
                    return new MockResponse().setResponseCode(200).setBody(carLocation)
                } 
            }
        })

        carInfo = new ClassPathResource(CAR_INFO_PATH).getFile().getText()

        carLocation = new ClassPathResource(CAR_LOCATION_PATH).getFile().getText()
    }


    def "When a resquest is performed to get car info then a list of cars are returned "() {

        when:
        def results = mockMvc.perform(get("/carInfo")
        ).andReturn().response

        then:
        results.status == HttpStatus.OK.value()
        def expected = "[{\"id\":2,\"code\":\"SAD005\",\"description\":\"Golf red color\",\"address\":Bremen,\"phone\":0067627621,\"postalCode\":00321}]"
        JSONAssert.assertEquals(new JSONArray(expected), new JSONArray(results.contentAsString), false)

    }
}

In the previous class, we make use of MockWebServer by adding a series of JSON responses through a dispatcher (dispatch method), which depends on the request being made. This is a way to add a response when we have different requests. However, if we have a single request, we can do it directly through enqueue.

Adding a Response to MockServer via enqueue

We can perform an integrated test where we make a single call using enqueue:

mockBackEnd.enqueue(new MockResponse().setBody(carInfo).addHeader("Content-Type", "application/json"))

Adding a Response to MockServer via dispatch

In many cases, we will need to perform an integrated test where we make multiple calls using WebClient. For those cases, it is better to use the dispatch method:

mockBackEnd.setDispatcher(new Dispatcher() {
            @Override
            MockResponse dispatch(@NotNull RecordedRequest recordedRequest) throws InterruptedException {
                if (recordedRequest.getPath().startsWith("/carworkshop/car-info")) {
                    return new MockResponse().setResponseCode(200).setBody(carInfo)
                } else if (recordedRequest.getPath().startsWith("/carworkshop/car-location")) {
                    return new MockResponse().setResponseCode(200).setBody(carLocation)
                } 
            }
        })

Conclusion

This refactoring entry demonstrates adding MockWebServer with WebClient of Spring for integrated testing in our application.

If you need more information, you can leave us a comment or send an email to refactorizando.web@gmail.com You can also contact us through our social media channels on Facebook or twitter and we will be happy to assist you!!

Leave a Reply

Your email address will not be published. Required fields are marked *