MockWebServer en WebClient de Spring

MockWebServer con WebClient

MockWebServer con WebClient


En este artículo vamos a profundizar como realizar test integrados utilizando MockWebServer en WebClient de Spring. La utilización de MockWebServer nos va a permitir poder mockear cualquier petición que se haga através de nuestro WebClient.

MockWebServer actúa como un servidor web, al cual intercepta la petición realizada y devuelve una respuesta con un body previamente establecida.

Usando MockWebServer

Dependencias de MockWebServer

Vamos a añadir las siguientes dependencias añadir las librerías necesarias:

    <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>

Para poder utilizar las librerías hemos añadido tanto la librería mockwebserver como la de okhttp.

Añadiendo MockWebServer a nuestros test

Vamos a añadir MockWebServer a nuestros test con 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()
    }

}

Como podemos ver en este fragmento de código, hemos añadido la clase MockWebServer la cual ha sido importada como static.

A continuación, tenemos que arrancar el el MockWebServer antes de que comience ningún test a ejecutarse, sería como el @BeforeAll, añadiendo el puerto donde lo queremos levantar. Finalmente, el último paso de configuración sería hacer un shutdown del MockWebServer, una vez se han finalizado todos los test.

A continuación añadimos una clase que extiende de la clase abstracta anterior para hacer uso del 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)

    }
}

En la clase anterior hacemos uso del MockWebServer, añadiendo una serie de json a través de un dispatcher (método dispatch), que depende de la petición que se haga (request). Esta es una manera de añadir una respuesta cuando tenemos diferentes request, pero en cambio, si tenemos una única request lo podemos hacer de una forma directa a través de enqueue.

Añadir Response a MockServer a través de enqueue.

Si tenemos un test integrado en el cual se va a realizar una única llamada podemos realizarlo a través de enqueue:

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

Añadir Reponse a MockServer a través de dispatch

En muchas ocasiones vamos a tener que realizar un test integrado en el cual se realizan varias llamadas con WebClient, para esos casos, será mejor hacer uso del método dispatch:

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)
                } 
            }
        })

Conclusión

En esta entrada de refactorizando hemos visto como añadir un MockWebServer en un WebClient de Spring, para poder implementarlo en la parte de test integrado de nuestra aplicación.


Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *