Cómo escribir pruebas de software con IA: guía práctica
Aprende a escribir pruebas de software con IA, elegir casos útiles, revisar el código generado y realizar comprobaciones fiables sin confiar en todas las sugerencias.
Puntos clave
- Proporciona a la IA el comportamiento esperado, el código relevante y las convenciones de pruebas, no solo una petición de «escribir pruebas».
- Revisa personalmente los resultados esperados. Las pruebas generadas pueden repetir los mismos errores que la implementación.
- Ejecuta las pruebas en un entorno seguro, comprueba que detecten errores deliberados y conserva las pruebas útiles en tu flujo de trabajo habitual.
La IA puede ayudar a un desarrollador a redactar pruebas de software, identificar casos límite y explicar fallos. Pero una prueba convincente no es necesariamente correcta.
El enfoque más fiable es tratar a la IA como un colaborador que prepara borradores. Tú defines qué debe hacer el código, solicitas pruebas específicas y después verificas que esas pruebas detecten problemas reales.
Qué necesitas
Antes de empezar, reúne:
- Un pequeño fragmento de código: Basta con una función, un endpoint o un componente.
- Sus requisitos: Describe el comportamiento correcto, incluidos los errores y las condiciones límite.
- Tu configuración de pruebas actual: Incluye el lenguaje, el framework, el comando de pruebas y una prueba representativa.
- Un asistente de IA autorizado: Consulta la política de tu organización antes de compartir código fuente.
- Un entorno de ejecución seguro: Utiliza un entorno de pruebas local o un entorno aislado sin credenciales de producción.
Elimina secretos, información de clientes y registros sensibles de todo lo que compartas. Prioriza los datos de prueba sintéticos frente a las copias de registros de producción.
Paso a paso
1. Define el comportamiento antes de compartir la implementación
Empieza con una especificación en lenguaje natural. Sin ella, la IA podría limitarse a convertir la implementación actual, incluidos sus errores, en resultados esperados.
Por ejemplo:
`shipping_fee(subtotal_cents)` acepta un subtotal entero no negativo expresado en céntimos. El envío cuesta 500 céntimos para subtotales inferiores a 5.000 céntimos y es gratuito a partir de 5.000 céntimos. Los subtotales negativos provocan una excepción `ValueError`.
Esto te proporciona resultados que puedes comprobar de forma independiente. También evita ambigüedades sobre las unidades monetarias y el umbral de envío gratuito.
Si los requisitos no están claros, pide al asistente que enumere sus preguntas antes de escribir pruebas. No dejes que invente silenciosamente el comportamiento para entradas no admitidas.
2. Proporciona a la IA instrucciones de prueba específicas
Proporciona la función, su especificación y una prueba relacionada que muestre las convenciones de tu proyecto. Incluye las dependencias relevantes, pero evita subir todo el repositorio innecesariamente.
Utiliza una instrucción como esta:
Escribe pruebas unitarias para la siguiente función utilizando `unittest`, incluido en Python. Sigue la especificación proporcionada y el estilo de las pruebas existentes. Primero enumera los casos que recomiendas y los requisitos que no estén claros. No modifiques el código de producción ni añadas dependencias. Mantén las pruebas deterministas y explica qué verifica cada caso.
Para otros proyectos, sustituye el lenguaje y el framework por los de tu configuración actual.
Separar la planificación de las pruebas de la generación de código facilita la detección de suposiciones incorrectas.
3. Revisa los casos propuestos
Pide una lista breve de casos antes de aceptar el código generado. Busca lo siguiente:
- Comportamiento normal: Una entrada válida habitual.
- Límites: Valores justo por debajo, en el umbral y por encima de él.
- Comportamiento ante fallos: Entradas no válidas o fallos de dependencias contemplados en los requisitos.
- Casos de regresión: Entradas que anteriormente causaron un error.
Para el ejemplo del envío, los subtotales útiles incluyen 0, 4.999, 5.000 y 5.001 céntimos, además de un valor negativo.
Elige el nivel de pruebas adecuado. Las pruebas unitarias comprueban pequeñas partes de la lógica. Las pruebas de integración comprueban interacciones, como las consultas a bases de datos. Las pruebas de extremo a extremo comprueban flujos de usuario completos.
No pidas a la IA que cubra todos los niveles a la vez. Empieza por el alcance útil más pequeño.
4. Genera un archivo de pruebas pequeño y legible
Pide al asistente que implemente los casos aprobados. Procura que el primer conjunto sea lo bastante pequeño como para revisarlo línea por línea.
Suponiendo que la función esté en `shipping.py`, un borrador podría ser así:
```python
import unittest
from shipping import shipping_fee
class ShippingFeeTests(unittest.TestCase):
def test_shipping_fee_boundaries(self):
cases = [
(0, 500),
(4999, 500),
(5000, 0),
(5001, 0),
]
for subtotal, expected in cases:
with self.subTest(subtotal=subtotal):
self.assertEqual(
shipping_fee(subtotal),
expected,
)
def test_negative_subtotal_is_rejected(self):
with self.assertRaises(ValueError):
shipping_fee(-1)
if __name__ == "__main__":
unittest.main()
```
Observa que los valores esperados proceden de la especificación. Las pruebas no reproducen el cálculo del envío para obtener sus resultados.
Comprueba las importaciones, las firmas de las funciones, los elementos de preparación de las pruebas y las aserciones. La IA puede hacer referencia a funciones auxiliares o métodos que no existen en tu proyecto.
5. Ejecuta las pruebas e investiga los fallos
Para el ejemplo anterior, guarda el archivo como `test_shipping.py` y ejecuta lo siguiente desde el directorio del proyecto:
```bash
python -m unittest test_shipping.py
```
Utiliza el comando establecido en tu proyecto para otras configuraciones.
Revisa el código generado antes de ejecutarlo, especialmente si instala paquetes, accede a archivos o realiza llamadas de red. La ejecución satisfactoria de las pruebas no debería requerir acceso al entorno de producción.
Cuando algo falle, clasifica el problema:
- ¿La prueba interpreta mal el requisito?
- ¿La configuración o la importación son incorrectas?
- ¿La implementación contiene un error?
Comparte con el asistente la salida relevante del fallo después de eliminar la información sensible. Pídele que explique la causa antes de sugerir cambios. Nunca aceptes «correcciones» que se limiten a debilitar las aserciones para que las pruebas pasen.
6. Comprueba si las pruebas detectan un error
Que las pruebas pasen no demuestra por sí solo que sean útiles.
Introduce temporalmente un pequeño defecto deliberado en una copia de trabajo local. Por ejemplo, cambia la condición de envío gratuito de «a partir de 5.000» a «por encima de 5.000».
La prueba para exactamente 5.000 céntimos debería fallar. Si no lo hace, investiga la prueba o comprueba si realmente se está ejecutando. Después, revierte el defecto deliberado.
Esta es una forma sencilla de realizar pruebas de mutación: comprobar si las pruebas detectan un comportamiento incorrecto.
7. Añade las pruebas revisadas a tu flujo de trabajo habitual
Una vez que las pruebas sean fiables, incorpóralas al control de versiones junto con el código relevante y ejecútalas en la integración continua.
Mantén las pruebas reproducibles. Controla el tiempo y la aleatoriedad cuando sea necesario, y aísla los servicios externos al probar la lógica local. Utiliza pruebas de integración separadas para verificar las interacciones reales.
Cuando la IA sugiera casos adicionales, da prioridad a los riesgos para el negocio y a los errores conocidos. Generar más pruebas no significa automáticamente tener mejores pruebas.
Errores comunes
- Tratar la implementación como si fuera la especificación: Esto puede perpetuar defectos existentes.
- Comprobar únicamente que el código se ejecuta: Incluye aserciones sobre resultados significativos, cambios de estado o errores exigidos por los requisitos.
- Simularlo todo: Un uso excesivo de simulaciones puede ocultar fallos en las interacciones.
- Perseguir únicamente la cobertura: Las líneas ejecutadas pueden seguir careciendo de aserciones útiles.
- Aceptar reescrituras automáticas: Revisa los cambios tanto en el código de producción como en las pruebas.
- Dejar sin resolver las pruebas inestables: La temporización, las redes y el estado compartido sin controlar socavan la confianza.
Herramientas útiles
- [Claude](/tools/claude): Útil para debatir requisitos, redactar casos de prueba y revisar la salida de los fallos. Verifica sus sugerencias en tu proyecto.
- [Amazon Q Developer](/tools/amazon-q-developer): Una opción para programar con asistencia de IA que también ofrece capacidades de análisis de seguridad y transformación. Revisa el código de pruebas generado antes de adoptarlo.
- [Buddy AI Sandboxes](/tools/buddy-ai-sandboxes): Proporciona entornos aislados en la nube para ejecutar y probar código escrito por agentes de IA.
- [Mintlify](/tools/mintlify): Ayuda a redactar y mantener documentación para desarrolladores. Una documentación clara del comportamiento puede proporcionar un mejor contexto para las instrucciones de generación de pruebas.
Preguntas frecuentes
¿Puede la IA escribir pruebas para código existente?
Sí. Proporciona el código relevante, el comportamiento esperado y las convenciones de pruebas existentes. En el caso de comportamientos no documentados, distingue entre conservar el comportamiento actual y confirmar que es correcto.
¿Deberían las pruebas generadas por IA sustituir a las pruebas manuales?
No. Pueden apoyar las comprobaciones automatizadas, pero las pruebas exploratorias y la revisión humana siguen siendo importantes, especialmente para la usabilidad, los requisitos poco claros y los flujos de trabajo inesperados.
¿Cómo sé si una prueba generada por IA es buena?
Comprueba un requisito claro, produce resultados reproducibles y falla cuando ese comportamiento deja de cumplirse. Deberías poder explicar su resultado esperado sin depender de la explicación de la IA.