Cuando escribes software, puedes confirmar que funciona correctamente a través de pruebas. Las pruebas pueden definirse ampliamente como el proceso de ejecutar un software en maneras de garantizar que se comporte según lo previsto.
Las pruebas exitosas pueden darte la confianza de que, a medida que agregas nuevo código, funciones o incluso actualizar tus dependencias, el software que ya escribiste sigan funcionando de la manera que esperas. Las pruebas también pueden ayudar a proteger tu ante situaciones improbables o entradas inesperadas.
Estos son algunos ejemplos de comportamiento en la Web que podrías probar:
- Asegurarse de que la función de un sitio web funcione correctamente cuando se hace clic en un botón
- Confirmar que una función compleja produce los resultados correctos.
- Completar una acción que requiera el acceso del usuario
- Verificar que un formulario informe correctamente un error cuando se ingresan datos con formato incorrecto
- Asegurarse de que una aplicación web compleja siga funcionando cuando un usuario tiene tiene un ancho de banda bajo o se queda sin conexión.
Pruebas automáticas y manuales
Puedes probar tu software de dos maneras generales: pruebas automatizadas y manuales y pruebas.
Las pruebas manuales involucran a personas que ejecutan software directamente, como cargar un sitio web en su navegador y confirmar que se comporta según lo esperado. Manuales son fáciles de crear o definir. Por ejemplo, ¿puede tu sitio cargarse? ¿Puedes realizar estas acciones?, pero cada ejecución cuesta una enorme cantidad de tiempo humano. Aunque los seres humanos son muy creativos, lo que puede habilitar un tipo de prueba conocidas como pruebas de exploración, aún podemos ser malos para detectar fallas o incoherencias, especialmente cuando se hace la misma tarea muchas veces.
Las pruebas automatizadas son cualquier proceso que permite codificar y ejecutar pruebas repetidamente una computadora para confirmar el comportamiento previsto del software sin que una persona realice pasos repetidos, como la configuración o la comprobación de los resultados. Es importante destacar que, una vez que se configuran las pruebas automatizadas, se pueden ejecutar con frecuencia. Esta sigue siendo una definición muy amplia y vale la pena señalar que la automatización las pruebas toman todo tipo de formas. La mayoría de este curso abarca con las pruebas automatizadas como práctica.
Las pruebas manuales tienen su lugar, a menudo como precursoras de la escritura automatizada pero también cuando las pruebas automatizadas se vuelven poco confiables y de amplio alcance, o difícil de manejar.
Aspectos básicos a través de un ejemplo
Para nosotros, como desarrolladores web que escriben JavaScript o lenguajes relacionados, una comunicación concisa la prueba automatizada podría ser una secuencia de comandos como esta que se ejecuta todos los días, tal vez a través de Node.js o cargándolo en un navegador:
import { fibonacci } from "../src/math.js";
if (fibonacci(0) !== 0) {
throw new Error("Invalid 0th fibonacci result");
}
const fib13 = fibonacci(13);
if (fib13 !== 233) {
throw new Error("Invalid 13th fibonacci result, was=${fib13} wanted=233");
}
Este es un ejemplo simplificado que proporciona las siguientes estadísticas:
Esta es una prueba porque ejecuta algún software (el Fibonacci función) y garantiza que su comportamiento funciona como estaba previsto, ya que compara sus resultados con los valores esperados. Si el comportamiento no es correcto, se produce un error, que JavaScript se expresa a través de un
Error
.Aunque es posible que estés ejecutando esta secuencia de comandos manualmente en tu terminal o en un navegador, esta sigue siendo una prueba automatizada porque se puede ejecutar varias veces sin tener que realizar ningún paso individual. La página siguiente, donde pruebas ejecutadas, explica más.
Aunque esta prueba no usa ninguna biblioteca, es JavaScript el que se ejecute en cualquier lugar; sigue siendo una prueba. Hay muchas herramientas que pueden ayudarte escribir pruebas, incluidas las que se abordarán más adelante en este curso, pero todos siguen trabajando en el principio fundamental de causar un error si algo sale mal.
Cómo probar bibliotecas en la práctica
La mayoría de las bibliotecas o frameworks de prueba integrados proporcionan dos primitivas principales hacen que las pruebas sean más fáciles de escribir: aserciones y una forma de definir pruebas independientes. Estas se tratarán en detalle en la siguiente sección, las aserciones y otras primitivas. Sin embargo, en términos generales, recuerda que casi todas las pruebas que ves o escribes con este tipo de primitivas.
Las aserciones son una forma de combinar la verificación de un resultado y la causa de un error si
algo sale mal. Por ejemplo, puedes hacer que la prueba anterior sea más concisa
Para ello, presenta assert
:
import { fibonacci } from "../src/math.js";
import { assert } from "a-made-up-testing-library";
assert.equal(fibonacci(0), 0, "Invalid 0th fibonacci result");
assert.equal(fibonacci(13), 233, "Invalid 13th fibonacci result");
Puedes mejorar aún más esta prueba definiendo pruebas independientes, opcionalmente agruparse en paquetes. El siguiente paquete prueba de forma independiente el hardware de Fibonacci y la función Catalán:
import { fibonacci, catalan } from "../src/math.js";
import { assert, test, suite } from "a-made-up-testing-library";
suite("math tests", () => {
test("fibonacci function", () => {
assert.equal(fibonacci(0), 0, "Invalid 0th fibonacci result");
assert.equal(fibonacci(13), 233, "Invalid 13th fibonacci result");
});
test("relationship between sequences", () => {
const numberToCheck = 4;
const fib = fibonacci(numberToCheck);
const cat = catalan(numberToCheck);
assert.isAbove(fib, cat);
});
});
En este contexto de pruebas de software, test como sustantivo se refiere a un caso de prueba: un escenario único, independiente, tratable, como la "relación entre secuencias" caso de prueba del ejemplo anterior.
Las pruebas con nombre individual son útiles para las siguientes tareas, entre otras:
- Determinar cómo una prueba tiene éxito o falla con el tiempo
- Destacar un error o una situación por su nombre para que puedas probar fácilmente que el que tu caso actual se resuelva.
- Ejecución de algunas pruebas de forma independiente de otras, por ejemplo, a través de un filtro glob
Una forma de entender los casos de prueba es usar las “tres A” de la prueba de unidades: organizar, actuar y afirmar. En esencia, cada caso de prueba hará lo siguiente:
- Organiza algunos valores o estados (estos podrían ser datos de entrada hard-coded).
- Realiza una acción, como llamar a un método.
- Confirma los valores de salida o el estado actualizado (mediante
assert
).
La escala de las pruebas
En las muestras de código de la sección anterior, se describe una prueba de unidades, ya que se probar partes menores del software, a menudo enfocándose en un solo archivo, y, en este solo el resultado de una única función. La complejidad de las pruebas aumenta a medida que considera el código de múltiples archivos, componentes o incluso diferentes (a veces fuera de tu control, como un servicio de red o la el comportamiento de una dependencia externa). Por este motivo, los tipos de pruebas suelen llamarse según su alcance o escala.
Además de las pruebas de unidades, hay algunos ejemplos de otros tipos de pruebas: componentes pruebas, pruebas visuales y pruebas de integración. Ninguno de estos nombres tiene definiciones más rigurosas que pueden tener significados distintos según el base de código, así que recuerda usarlos como guía e idear definiciones que funcionen para ti. Por ejemplo, ¿qué es un componente que se está probando en tu sistema? Para Desarrolladores de React, esto puede asignarse literalmente a un “componente de reacción”, pero podría tienen un significado diferente para los desarrolladores en otros contextos.
La escala de una prueba individual puede ubicarla dentro de un concepto a menudo denominado como la "pirámide de prueba", que puede ser una buena regla general y cómo se ejecuta.
Esta idea se ha iterado y se han desarrollado otras formas más populares, como el diamante de prueba o el cono de hielo. Tus prioridades de redacción de exámenes probablemente sean exclusivas de tu base de código. Sin embargo, una función común es que las pruebas más simples, como las pruebas de unidades, tienden a ser más rápidas de ejecutar y más fáciles de escribir (por lo que tendrás más de ellas) y prueban un alcance limitado, mientras que las pruebas complejas, como las pruebas de extremo a extremo, difíciles de escribir, pero pueden probar un alcance más amplio. De hecho, la capa superior de muchas prueba de “formas” suele ser una prueba manual, porque cierta interacción del usuario demasiado complejo para codificarlo en una prueba automatizada.
Estos tipos se ampliarán en tipos de automatización pruebas.
Verifica tus conocimientos
¿Qué primitivas proporcionan la mayoría de las bibliotecas de prueba y frameworks?
assert()
y sus variaciones tienden a incluirse porque facilitan las verificaciones
escribir.test()
se incluye en casi todas las pruebas.
corredores. Es importante porque el código de prueba no se ejecuta en el nivel superior.
de un archivo, lo que permite que el ejecutor de pruebas trate cada caso de prueba como un
unidad independiente.