Dónde se ejecutan las pruebas

Por lo general, las pruebas automatizadas se pueden ejecutar ejecutando una secuencia de comandos de forma manual o con un asistente de un framework de pruebas, que se suele llamar ejecutor de pruebas, para encontrar y ejecutar pruebas. Sin embargo, es posible que no siempre debas ejecutar tus secuencias de comandos de forma manual. Hay varias formas de ejecutar tus pruebas que pueden proporcionar comentarios y confianza en diferentes momentos del ciclo de vida de desarrollo.

Secuencia de comandos de requisitos previos

Los proyectos web suelen tener un archivo de configuración (el archivo package.json) que configura npm, pnpm, Bun o similares. Este archivo de configuración contiene las dependencias de tu proyecto y otra información, además de secuencias de comandos auxiliares. Estas secuencias de comandos auxiliares pueden incluir la manera de compilar, ejecutar o probar tu proyecto.

Dentro de package.json, deberás agregar una secuencia de comandos llamada test que describa cómo ejecutar las pruebas. Esto es importante porque, cuando usas npm o una herramienta similar, la secuencia de comandos"test" tiene un significado especial. Esta secuencia de comandos puede apuntar a un solo archivo que arroja una excepción, como node tests.js, pero te recomendamos que la uses para apuntar a un ejecutor de pruebas establecido.

Si usas Vitest como ejecutor de pruebas, tu archivo package.json se verá de la siguiente manera:

{
  "name": "example-project",
  "scripts": {
    "start": "node server.js",
    "test": "vitest --run"
  }
}

Si ejecutas npm test con este archivo, se ejecutará el conjunto de pruebas predeterminado de Vitest una vez. En Vitest, la opción predeterminada es buscar todos los archivos que terminan con ".test.js" o similares y ejecutarlos. Según el ejecutor de pruebas que elijas, el comando puede ser un poco diferente.

Elegimos usar Vitest, un framework de prueba cada vez más popular, para obtener ejemplos de este curso. Puedes obtener más información sobre esta decisión en Vitest as a test runner. Sin embargo, es importante recordar que los frameworks y los ejecutores de pruebas (incluso entre lenguajes) tienden a tener una misma expresión vernácula.

Invocación de prueba manual

La activación manual de las pruebas automatizadas (como el uso de npm test en el ejemplo anterior) puede ser práctica mientras trabajas de forma activa en una base de código. Escribir pruebas para una función mientras la desarrollas puede ayudarte a tener una idea de cómo debería funcionar la función, lo que aborda el concepto de desarrollo basado en pruebas (TDD).

Los ejecutores de pruebas suelen tener un comando corto que puedes invocar para ejecutar algunas o todas tus pruebas y, posiblemente, un modo de supervisor que vuelve a ejecutar las pruebas a medida que las guardas. Todas estas son opciones útiles mientras se desarrolla una función nueva y están diseñadas para facilitar la escritura de una función nueva, sus pruebas o ambas, todo con comentarios rápidos. Vitest, por ejemplo, funciona en modo de observador de forma predeterminada: el comando vitest supervisará los cambios y volverá a ejecutar cualquier prueba que encuentre. Te recomendamos que dejes este campo abierto en otra ventana mientras escribes pruebas para que puedas obtener comentarios rápidos sobre tus pruebas a medida que las desarrollas.

Algunos ejecutores también te permiten marcar pruebas como only en tu código. Si tu código incluye pruebas de only, solo estas se activarán cuando ejecutes pruebas, lo que hace que el desarrollo de pruebas sea más rápido y fácil de solucionar. Incluso si todas las pruebas se completan rápidamente, usar only puede reducir la sobrecarga y quitar la distracción de ejecutar pruebas que no están relacionadas con la función o la prueba en la que estás trabajando.

Para proyectos pequeños, en especial aquellos con un solo desarrollador, es posible que también quieras desarrollar el hábito de ejecutar todo el paquete de pruebas de la base de código con regularidad. Esto es muy útil si las pruebas son pequeñas y se completan rápidamente (en no más de unos segundos para todas las pruebas), de modo que puedas asegurarte de que todo funcione antes de continuar.

Cómo ejecutar pruebas como parte del envío previo o la revisión

En muchos proyectos, se opta por confirmar que una base de código funcione correctamente cuando el código se vuelve a combinar en su rama main. Si eres nuevo en las pruebas, pero ya contribuiste a proyectos de código abierto en el pasado, es probable que hayas notado que parte del proceso de solicitud de extracción (PR) confirma que todas las pruebas del proyecto están aprobadas, lo que significa que tu nueva contribución emocionante no afectó negativamente al proyecto existente.

Si ejecutas tus pruebas de manera local, el repositorio en línea de tu proyecto (por ejemplo, GitHub o algún otro servicio de hosting de código) no sabrá que tus pruebas están aprobadas, por lo que ejecutar las pruebas como una tarea de envío previo les dejará en claro a todos los colaboradores que todo funciona.

GitHub, por ejemplo, se refiere a estas como “verificaciones de estado” que puedes agregar a través de Acciones de GitHub. Las acciones de GitHub son, en esencia, un tipo de prueba: cada paso debe completarse con éxito (no fallar ni arrojar una Error) para que se apruebe la acción. Puedes aplicar acciones a todas las PR de un proyecto, y un proyecto puede requerir que las acciones pasen antes de que aportes código. La acción predeterminada de Node.js de GitHub ejecuta npm test como uno de sus pasos.

Captura de pantalla del proceso de prueba de GitHub Actions
Captura de pantalla del proceso de prueba de GitHub Actions.

Este enfoque de prueba intenta asegurarse de que tu base de código siempre esté “verde” ya que no acepta el código que no ejecuta correctamente sus pruebas.

Ejecuta pruebas como parte de la integración continua

Una vez que se acepte la solicitud de extracción verde, la mayoría de las bases de código ejecutan pruebas de nuevo según la rama main de tu proyecto, en lugar de la solicitud de extracción anterior. Esto puede ocurrir de inmediato o con regularidad (por ejemplo, cada hora o por la noche). Estos resultados suelen mostrarse como parte de un panel de integración continua (CI) que muestra el estado general del proyecto.

Este paso de CI puede parecer redundante, en especial para proyectos con bases de código pequeñas; las pruebas se pasan durante la revisión, por lo que deben aprobarse una vez que se produce un cambio. Sin embargo, esto no siempre es así. Las pruebas pueden fallar repentinamente, incluso después de producir con éxito resultados verdes. Estos son algunos de los motivos:

  • Se aceptaron varios cambios "a la vez", a veces conocidos como condición de carrera, y se afectan entre sí de maneras sutiles y no probadas.
  • Tus pruebas no son reproducibles o prueban un código "frágil", es decir, pueden pasar y fallar sin cambios en el código.
    • Esto puede ocurrir si dependes de sistemas externos a tu base de código. En el caso de un proxy, imagina realizar una prueba si es Math.random() > 0.05, ya que esto fallaría de forma aleatoria el 5% de las veces.
  • Algunas pruebas son demasiado costosas o costosas para ejecutarlas en todas las relaciones públicas, como las pruebas de extremo a extremo (más información sobre esto en los tipos de pruebas automatizadas), y pueden interrumpirse con el tiempo sin generar alertas en todo momento.

Ninguno de estos problemas es imposible de solucionar, pero vale la pena tener en cuenta que las pruebas y el desarrollo de software en general nunca serán una ciencia exacta.

Un interludio en la reversión

Cuando las pruebas se ejecutan como parte de la integración continua, incluso cuando estas se ejecutan como parte de una verificación de estado, es posible que la compilación termine en un estado "rojo" o en otro estado que signifique que las pruebas fallan. Como se mencionó anteriormente, esto puede ocurrir por varios motivos, incluidas las condiciones de carrera en el envío de pruebas o las pruebas inestables.

Para proyectos más pequeños, tu instinto podría ser tratarlos como una crisis. Detén todo, revierte o revierte el cambio ofensivo y vuelve a un estado correcto conocido. Este puede ser un enfoque válido, pero es importante recordar que las pruebas (y el software en general) son un medio para lograr un fin, no un objetivo en sí. Tu objetivo probablemente sea escribir software, no hacer que todas las pruebas sean exitosas. En su lugar, puedes adelantar si sigues el cambio rotundo con otro cambio que corrija las pruebas con errores.

Por otro lado, es posible que hayas visto o trabajado en proyectos grandes que existen en un estado perpetuamente roto. O lo que es peor, el proyecto grande tiene una prueba inestable que se interrumpe con suficiente frecuencia como para causar fatiga por alarmas en los desarrolladores. A menudo, este es un problema existencial que deben resolver los líderes: estas pruebas incluso pueden desactivarse porque se las considera "obstaculizar el desarrollo".

No hay una solución rápida para esto, pero puede ser útil escribir pruebas con mayor confianza (mejora) y reducir el alcance de las pruebas (simplificación) para que las fallas se identifiquen con mayor facilidad. Una mayor cantidad de pruebas de componentes o pruebas de integración (más información sobre tipos en Tipos de pruebas automatizadas) puede proporcionar más confianza que una gran prueba de extremo a extremo difícil de mantener y que intenta hacer todo a la vez.

Recursos

Verifica tus conocimientos

¿Cuál es el nombre de la secuencia de comandos especial que npm y programas similares buscan durante las pruebas?

check
prueba
envío previo
verify