Introducción

En este post aprenderás qué es el unit testing y diferentes herramientas que se pueden utilizar, así como su implementación en proyectos de React.

¿Qué son las pruebas unitarias o Unit testing?

Con Unit Testing, nos referimos a programar tests que nos sirven para comprobar que un bloque con una funcionalidad específica de nuestro código funciona como esperamos.

¿Cuál es su estructura?

El cuerpo de un test consta de tres partes:

  • Arrange:

Es el primer paso, donde se crean las variables y se preparan los recursos a utilizar (componentes, clases…).

  • Act:

Donde se ejecutan las acciones sobre el componente, que provocarán el resultado que queremos comprobar.

  • Assert:

El último paso, donde se verifica si el componente ha realizado la funcionalidad esperada.

¿Cómo realizar un test en React?

En nuestro caso, vamos a utilizar Visual Studio Code para programar los test. Empezaremos creando un proyecto nuevo de React llamado “unittestreact”.

Una vez hecho, en el directorio /src crearemos una carpeta llamada components, donde iremos incluyendo los componentes que utilicemos así como sus correspondientes test.

NUESTRO PRIMER TEST

Empezaremos con un test básico para ir familiarizándonos. Para ello, en components crearemos una carpeta “TestBasico” donde añadiremos dos archivos nuevos:

  • TestBasico.js

En este archivo programaremos el componente a testear, en este caso, un formulario que contiene un campo de texto donde el usuario escribirá un país y que, al darle al botón de enviar, mostrará el valor mediante un h2.

Código TestBasico.js

Como se puede observar en la imagen, añadiremos un atributo data-testid a algunos elementos para poder acceder a ellos posteriormente desde el test.

Una vez programado, la vista quedaría de la siguiente manera:

Vista de TestBasico.js
  • TestBasico.test.js

Ahora vamos a centrarnos en el test, donde empezaremos importando React, el archivo “TestBasico.js” que hemos creado antes y la librería “@testing-library/react”.

Crearemos un test indicando en el nombre lo que queremos comprobar, en este caso, que el valor que introduzcamos en el input sea el mismo que se mostrará en el h2 después de pulsar el botón para enviar el formulario.

Asimismo, utilizaremos un arrow function para crearlo.

La parte de arrow function junto al nombre del test es la siguiente y es equivalente a function(){}:

Nombre de test y arrow function

A continuación programaremos dicho test respetando las tres partes anteriormente explicadas del modelo AAA (Arrange, Act, Assert).

Código TestBasico.test.js

En la parte de Arrange, como podemos apreciar en la imagen, llamaremos al método render pasándole como parámetro nuestro componente e importaremos el método getByTestId de la respuesta, que nos servirá para buscar los elementos del mismo que tengan el atributo data-testid.

Asimismo, crearemos las constantes input, button y result, que accederán a los elementos del componente mediante el id.

Además, crearemos la constante inputValue donde añadiremos el valor “España” para poder escribirlo en el input y mostrarlo en el h2.

Seguimos con la parte de Act, donde le indicaremos al test que el valor del input tiene que ser igual a “España” y posteriormente añadiremos un button.click() para que el formulario se envíe y podamos comprobar el resultado.

Por último, en la parte de Assert, comunicaremos el resultado esperado con expect().toBe(). El cual será que el contenido del h2 sea el mismo que el valor del input.

Para pasar el test, abriremos el terminal y escribiremos npm test.

Ejecutar test

El test pasará y nos lo comunicará con un PASS:

Test pasado correctamente

Pero, ¿qué pasaría si le cambiamos algo del código?

Pongamos el caso de que, por ejemplo, quisiéramos enviar un mensaje al usuario cuando envía el formulario. Modificaríamos el código, indicándole en  el método de cargarResultado que resultado será el string “Gracias por enviarnos la información” en vez del valor del input.

Modificación del resultado

Al pasar de nuevo el test, nos aparecería el siguiente error:

Test falla al pasarlo

De este modo, si estamos programando y tocamos algo del código que altera la funcionalidad anterior, los test nos comunican de forma eficaz donde falla para que lo solucionemos, bien, actualizando el test o dejando el código como estaba anteriormente.

TEST SNAPSHOT

Nuestro segundo test, será una demostración de cómo utilizar snapshot.

Este tipo de test verifica que el HTML que genera nuestro código es el mismo que cuando creamos el snapshot. Es como si hiciéramos una foto del código y posteriormente el test se asegurara de que todo siga estando en su lugar.

Para empezar el test, crearemos una carpeta “TestSnapshot”, donde añadiremos los siguientes archivos:

  • TestSnapshot.js

Como en el test anterior, en este archivo programaremos la funcionalidad que queremos que tenga el componente.

En este caso, haremos un menú con varias películas que se muestran en una lista.

El código del componente sería el siguiente:

Código TestSnapshot.js

Quedando la vista como en la foto que podréis ver a continuación:

Vista de TestSnapshot.js
  • TestSnapshot.test.js

Este archivo lo crearemos una vez hayamos comprobado que el componente que queremos testear funciona.

Aquí crearemos el test, empezando como en el anterior, importando React y el componente que vamos a utilizar (“TestSnapshot.js”).

Procederemos a programar el test poniéndole de nombre “render a snapshot” y utilizando un arrow function para crearlo.

Posteriormente, llamaremos al elemento raíz del componente con la constante {baseElement} y el método render.

Finalmente, le escribiremos la línea expect(baseElement).toMatchSnapshot, la cual creará el snapshot la primera vez que pasemos el test (guardándolo en el directorio “__snapshots__”) y en los siguientes test buscará y comparará el código con el archivo que creó.

Código TestSnapshot.test.js

Una vez finalizado, procederemos a ejecutarlo.

La primera vez que el test pase, nos aparecerá conforme se ha creado un nuevo snapshot, éste se crea dentro de una carpeta llamada “__snapshots__” situada en el directorio “TestSnapshot”:

Snapshot creado

Si cambiáramos algo del código, como añadir una nueva película y ejecutáramos el test, nos aparecía el siguiente error:

Test Snapshot falla al pasarlo debido al cambio realizado

En este error, podremos ver en rojo lo que hemos recibido que no coincide con el snapshot (en este caso, la nueva película introducida).

Para actualizar el test, tendríamos que presionar la tecla “u” y así obtendríamos un nuevo snapshot con la modificación deseada, donde nos especificaría snapshot updated, como podemos ver en la siguiente imagen:

Test Snapshot actualizado

TESTS CON MOCKS

Nuestro último test utilizará un mock.

La herramienta mock permite crear una clase, módulo o función falso que utilizaremos para sustituir en nuestro componente una dependencia real, y que el test compruebe su funcionamiento sin necesitar que dicha dependencia funcione correctamente. Un ejemplo de dependencia sería una llamada a una API externa que podría fallar en un momento determinado y que no debería afectar a nuestros test.

Para poder realizar este ejemplo, instalaremos axios en el proyecto, que es una librería opensource para hacer peticiones http fácilmente.

En primer lugar, crearemos el directorio “TestMock”, donde incluiremos la siguiente carpeta y archivos:

Empezaremos creando la carpeta “__mocks__” donde añadiremos una clase con una lista falsa de tres clientes así como un método falso que jest pueda utilizar en el test.

El archivo sería el siguiente:

  • MockClienteWeb.js

Dentro de ésta clase, programaremos un static listaClientes, que contendrá un data con un array de customers, formado por tres clientes diferentes.

Asimismo, crearemos el método cargarClientes, que devolverá una promesa con la lista de clientes, al igual que el método original.

El código sería el siguiente:

Código MockClienteWeb Parte 1
Código MockClienteWeb Parte 2

Continuaremos creando los siguientes archivos dentro de “TestMock” :

  • ClienteWeb.js

Empezaremos programando la clase ClienteWeb, que tendrá un método cargarClientes encargado de llamar a una API externa para recoger datos y que devolverá una promesa con una lista de clientes.

Código ClienteWeb.js
  • TestMock.js

Este es el componente a testear, donde llamaremos al método cargarClientes de “ClienteWeb”, guardando la lista recibida en el state. Asimismo, pintaremos la información de dicha lista en una tabla de HTML utilizando map.

El código sería el siguiente:

Parte 1 del código de TestMock.js
Parte 2 del código de TestMock.js

Quedando la vista de la siguiente forma:

Vista de TestMock.js
  • TestMock.test.js

Para probar la herramienta mock, vamos a hacer diferentes test y una clase mock que se explica posteriormente:

Empezaremos con los imports de lo que necesitamos para realizar los test. En este caso los tres componentes que utilizaremos: TestMock, ClienteWeb y MockClienteWeb.

Imports de TestMock.test.js

Test Mock a Function

En este ejemplo mockearemos el método cargarClientes, es decir, crearemos un método falso que sustituirá al primero y podremos usarlo con jest.

Para hacer esto, utilizaremos el método jest.fn() con una implementación propia que devuelva una lista falsa y controlada por nosotros de clientes, y le inyectaremos al componente el cliente web modificado.

Asimismo, tendremos que utilizar await para esperar a que la llamada web se resuelva, puesto que es una promesa.

Y, por último, comprobaremos que la cantidad de clientes en pantalla sean tres (los mismos que definimos en la lista falsa).

Código Test «mock a function»

Test Spy a Function

Con este ejemplo, veremos cómo espiar una función y para qué vale.

El método jest.spyOn permite a jest conocer las llamadas que se han hecho a un objeto concreto, sin tener que llamar a jest.fn() o redefinir su funcionalidad. Para mostrar una opción diferente al test anterior, vamos a utilizar una clase llamada MockClienteWeb (la que creamos anteriormente) con la misma definición pública que la clase ClienteWeb, para inyectarla al componente sustituyendo la original. Esto nos permite redefinir el funcionamiento de módulos enteros y reducir/mockear dependencias enteras fácilmente.

(Para más información, haz click aquí para ir a la documentación oficial).

Código Test «spy a function»

Y con esto, tendremos varias formas distintas de implementar unit test en nuestros proyectos.

Conclusión

El uso de test es algo esencial para prevenir bugs y asegurarnos de que nuestro proyecto funciona correctamente.

Autor/a: Laura San Nicolás Sáez

Curso: Microsoft MCSA Web Applications + Microsoft MCSD App Builder + Xamarin

Centro: Tajamar

Año académico: 2019-2020

Código: https://github.com/lstajamar/UnitTestReact

Recursos utilizados:

Leave a Comment

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

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.