Testear Rest API con WebTestClient

En este artículo veremos la forma de testear una Rest API con WebTestClient.

Spring 5 y WebFlux

En versiones de Spring previas a la 5, se provee la clase RestTemplate para permitir realizar peticiones HTTP. Sin embargo, a partir de la versión 5 se recomienda el uso de WebClient que, entre otras ventajas, permite realizar peticiones no bloqueantes y trabajar directamente con tipos reactivos.

WebClient es parte del framework para aplicaciones reactivas conocido como WebFlux.

En general, el uso de WebClient requiere seguir los siguientes pasos:

  • Crear o inyectar una instancia de WebClient.
  • Especificar el método HTTP de la petición.
  • Especificar la URI del petición.
  • Especificar, en caso de corresponder, los encabezados de la petición.
  • Enviar la petición.
  • Consumir la respuesta del servicio.

¿Qué es WebTestClient?

WebTestClient es el cliente que utilizaremos para probar nuestros servicios. Internamente utiliza WebClient para realizar las peticiones y nos proporciona métodos para verificar las respuestas.

Testear Rest API con WebTestClient

Para probar los siguientes ejemplos puede utilizar el proyecto del siguiente artículo.

Enlazar a un Controller usando bindToController(Object…)

Podemos testear un controller individualmente usando el método WebTestClient.bindToController() para obtener una instancia de WebTestClient. Para esto le pasaremos a bindToController() una instancia del controller que vamos a testear, al cual inyectaremos un Mock de su dependencia. Haremos esto en los siguientes pasos:

  1. Crear los datos de prueba que retornará el Mock. El servicio retornará un listado de clientes, donde cada cliente estará representado por una instancia de la clase Customer, por lo que creamos un array de Customer que a continuación usaremos para crear el objeto de tipo Flux que será retornado por el servicio:
		Customer[] customers = {
				new Customer(1, "Juan", "Perez", "Programador"),
				new Customer(2, "Pedro", "Perez", "Manager")
		};
		
		Flux<Customer> customerFlux = Flux.just(customers);
  1. Crear el objeto Mock. Utilizamos Mockito para instanciar el componente CustomerService y establecer el objeto Flux<Customer> creado en el paso anterior:
		CustomerService service = Mockito.mock(CustomerService.class);
		when(service.getCustomers()).thenReturn(customerFlux);
  1. Instanciar WebTestClient con el método bindToController() pasando como parámetro una instancia de CustomerController a la cual, a su vez, inyectamos su dependencia en el constructor:
		WebTestClient client = 
				WebTestClient.bindToController(new CustomerController(service)).build();
  1. Enviar la petición GET y procesar la respuesta. Una vez inicializados los componentes y habiendo hecho el binding del cliente con el controller a testear podemos hacer la primera petición a nuestro endpoint. Para esto usaremos los siguientes métodos:
  1. client.get().uri(«/customer») especifica el tipo de petición y la URI del servicio.
  2. exchange() envía la petición que será manejada por el controller al que enlazamos el cliente.
  3. expectStatus().isOk() permite verificar que la respuesta del servicio es 200.
		client.get().uri("/customer")
			.exchange()
			.expectStatus().isOk()
			.expectBody()

  1. Verificar los datos de la respuesta usando JSONPath. JSONPath es un lenguaje de consulta para JSON que permite seleccionar y recuperar datos de un documento JSON (en nuestro caso de la respuesta del servicio que estamos testeando). JSONPath es el equivalente a XPath para XML. En el ejemplo veremos varias llamadas al método jsonPath() para acceder a los atributos de cada una de las entidades que queremos verificar.

A continuación se lista el código completo:

class HelloRestApiApplicationTests {

	@Test
	public void testGetCustomers() {
		Customer[] customers = {
				new Customer(1, "Juan", "Perez", "Programador"),
				new Customer(2, "Pedro", "Perez", "Manager")
		};
		
		Flux<Customer> customerFlux = Flux.just(customers);
		
		CustomerService service = Mockito.mock(CustomerService.class);
		when(service.getCustomers()).thenReturn(customerFlux);

		WebTestClient client = 
				WebTestClient.bindToController(new CustomerController(service)).build();

		client.get().uri("/customer")
			.exchange()
			.expectStatus().isOk()
			.expectBody()
			.jsonPath("$").isArray()
			.jsonPath("$").isNotEmpty()
			.jsonPath("$[0].id").isEqualTo(customers[0].getId())
			.jsonPath("$[0].firstName").isEqualTo(customers[0].getFirstName());
	}
}

Enlazar a un servidor usando bindToServer()

WebTestClient también nos permite hacer tests de integración enlazando el cliente a un servidor en ejecución.

En este caso los tests se harán en la aplicación desplegada en el servidor correspondiente, y previamente debemos inyectar las capas (controller, service, etc) con @Autowired para poder verificar la correcta integración de los componentes.

Para instanciar nuestro cliente usamos los métodos:

  • bindToServer() permite conectarse a un servidor en ejecución mediante un conector Netty.
  • baseUrl(«http://localhost:8080») configura la URI base.

Una vez obtenida la instancia de nuestro cliente podemos comenzar a realizar peticiones a los servicios de la misma forma que en el anterior ejemplo.

	@Test
	public void testGetCustomers() {
		
		WebTestClient webTestClient = WebTestClient.bindToServer()
				.baseUrl("http://localhost:8080")
				.build();
		
		Flux<Customer> result = 
				webTestClient.get().uri("/customer")
					.accept(MediaType.APPLICATION_JSON)
					.exchange()
                    .expectStatus().isOk()
					.returnResult(Customer.class).getResponseBody();
		
		result.subscribe(data -> System.out.println("-> " + data));
		
	}

Conclusión

WebTestClient es una herramienta poderosa para probar API Rest en aplicaciones Spring. Proporciona una API flexible y fácil de usar para realizar requests y aserciones, lo que permite a los desarrolladores probar exhaustivamente sus servicios. Al aprovechar WebTestClient en su estrategia de prueba, los desarrolladores pueden asegurarse de que sus API Rest sean sólidas, confiables y de alto rendimiento, lo que lleva a una mejor calidad general de la aplicación.


Te puede interesar

Crear microservicios con Spring Boot

En este artículo cubriremos los pasos necesarios para crear microservicios con Spring Boot, desplegarlo y acceder a los endpoints.

Seguir leyendo →

Configurar parámetros en Spring Rest API

Configurar parámetros en Spring Rest API es esencial, ya que esto facilita la transferencia de datos entre el cliente y el servidor.

Seguir leyendo →