Saltar al contenido
siesia

Tests de Python con IA: guía práctica con unittest

Aprende a pedir pruebas de Python a una IA, revisar sus resultados y ejecutarlas con unittest. Incluye código, casos límite y soluciones a errores.

Por Raúl · · 8 min de lectura
Tests de Python con IA: guía práctica con unittest — portada editorial de Siesia
Foto de Daniil Komov en Pexels · Ver fotografía original

Para crear tests de Python con IA, empieza por describir qué debe hacer la función, solicita casos con entradas y resultados concretos y ejecuta los tests fuera del chat. En este tutorial practicarás ese proceso con una función que limpia etiquetas. No necesitas capturas, extensiones de pago ni instalar paquetes de pruebas.

Está pensado para quien ya entiende variables, listas y funciones básicas. Si estás empezando con los asistentes, puedes consultar primero la guía de primeros pasos con ChatGPT. Los prompts también pueden utilizarse con otro asistente que genere código.

Qué necesitas y qué vas a comprobar

Necesitas Python 3 instalado, un editor de texto y una terminal. Abre PowerShell o Terminal y escribe python --version. Si no reconoce el comando, prueba python3 --version; en Windows también puede estar disponible py --version. Utiliza en todos los comandos siguientes el nombre que haya funcionado. Si ninguno funciona, debes instalar o configurar Python antes de continuar: una respuesta de la IA no sustituye al intérprete que ejecuta el programa.

Usaremos unittest, incluido en Python. Permite definir comprobaciones que comparan un resultado obtenido con el esperado y ejecutarlas juntas. La documentación oficial de unittest explica sus aserciones y comandos. No ejecutes pip install unittest: este ejemplo no lo necesita.

Trabaja en una carpeta nueva, por ejemplo pruebas_etiquetas. Crea allí dos archivos de texto llamados exactamente etiquetas.py y test_etiquetas.py. Evita que el editor añada .txt. Este ejercicio solo procesa listas en memoria; no debe acceder a cuentas, archivos personales ni servicios externos.

1. Define el comportamiento antes de pedir código

Imagina que una aplicación recibe etiquetas escritas por distintas personas. «Python», «PYTHON» y « python » deberían convertirse en una sola etiqueta. Antes de programarlo, establece estas reglas:

  • La entrada es una lista de textos; cualquier otro tipo produce TypeError.
  • Se quitan los espacios de los extremos y se reducen los espacios en blanco interiores a uno.
  • Se eliminan las etiquetas vacías y los duplicados sin distinguir mayúsculas.
  • Se mantiene el orden y la escritura de la primera aparición ya limpia.
  • Se devuelven como máximo cinco etiquetas, salvo que se indique otro límite entero positivo. Los booleanos no son límites válidos.
  • Se valida toda la lista, aunque se haya alcanzado el límite: no se ocultan elementos incorrectos al final.

Estas reglas forman el contrato de la función: son decisiones del ejemplo, no obligaciones universales. Si tu aplicación necesita distinguir mayúsculas o aceptar números, cambia primero el contrato. También queda fuera del alcance corregir faltas de ortografía, quitar tildes o decidir si dos palabras significan lo mismo.

2. Pide primero una tabla de casos a la IA

Copia este prompt y añade debajo las reglas anteriores:

Actúa como revisor de pruebas Python. Antes de escribir tests, crea una tabla con requisito, entrada, resultado esperado y motivo. Cubre usos normales, duplicados, espacios, lista vacía, límite y entradas inválidas. Usa las reglas que te doy como contrato; no deduzcas el resultado esperado de la implementación. Señala cualquier ambigüedad y no cambies el contrato por tu cuenta. No añadas paquetes ni accesos externos.

Comprueba tú los resultados de la tabla. Por ejemplo, ['A', 'a', 'B', 'C'] con límite 2 debe dar ['A', 'B']: el límite se aplica después de eliminar duplicados. Una IA podría esperar dos elementos de entrada y devolver solo ['A'], que no cumple la regla elegida.

Esta revisión previa ayuda a detectar pruebas que simplemente aceptarían un error del código. GitHub recomienda revisar el código generado frente a los requisitos y comprobarlo mediante pruebas; aquí lo aplicamos a una función pequeña.

3. Guarda una implementación concreta

Copia lo siguiente en etiquetas.py. Es una implementación didáctica del contrato, no una biblioteca para todos los proyectos.

def limpiar_etiquetas(etiquetas, limite=5):
    if not isinstance(etiquetas, list):
        raise TypeError('etiquetas debe ser una lista')
    if type(limite) is not int or limite < 1:
        raise ValueError('limite debe ser un entero positivo')
    resultado = []
    vistas = set()
    for etiqueta in etiquetas:
        if not isinstance(etiqueta, str):
            raise TypeError('cada etiqueta debe ser texto')
        limpia = ' '.join(etiqueta.split())
        clave = limpia.casefold()
        if limpia and clave not in vistas:
            vistas.add(clave)
            resultado.append(limpia)
    return resultado[:limite]

split() sin separador divide el texto por espacios en blanco y join() lo reconstruye con un único espacio. casefold() genera una forma de comparación sin distinción de mayúsculas; se guarda la etiqueta limpia original para no perder su escritura. Estas operaciones están descritas en la documentación de los tipos de Python.

La comprobación type(limite) is not int es intencionada: en Python los booleanos son un subtipo de los enteros y este contrato exige rechazarlos. La función revisa todos los elementos antes de recortar el resultado; de otro modo, podría aceptar una lista incorrecta solo porque el elemento problemático queda después del límite.

4. Solicita los tests y revisa que prueben tu función

Genera test_etiquetas.py usando únicamente unittest. Importa limpiar_etiquetas desde etiquetas; no copies su implementación dentro del test. Crea pruebas independientes para cada regla acordada y resultados esperados literales. Incluye el caso ['A', 3] con límite 1: debe lanzar TypeError aunque el primer elemento ya complete el límite. No cambies la función para hacer que una expectativa incorrecta pase. Explica qué requisito cubre cada prueba.

Compara la respuesta con esta batería de referencia y guarda el archivo. Cada método cuyo nombre empieza por test_ comprueba una regla. assertEqual compara resultados; assertRaises comprueba un error esperado.

import unittest
from etiquetas import limpiar_etiquetas

class PruebasEtiquetas(unittest.TestCase):
    def test_espacios(self):
        self.assertEqual(limpiar_etiquetas(['  IA   aplicada ', 'tPythonn']), ['IA aplicada', 'Python'])
    def test_duplicados(self):
        self.assertEqual(limpiar_etiquetas(['Python', 'PYTHON', 'python']), ['Python'])
    def test_vacias(self):
        self.assertEqual(limpiar_etiquetas(['', '  ', 't']), [])
    def test_limite(self):
        self.assertEqual(limpiar_etiquetas(['A', 'a', 'B', 'C'], 2), ['A', 'B'])
    def test_limite_por_defecto(self):
        self.assertEqual(limpiar_etiquetas(['A', 'B', 'C', 'D', 'E', 'F']), ['A', 'B', 'C', 'D', 'E'])
    def test_orden_y_primera_escritura(self):
        self.assertEqual(limpiar_etiquetas(['  Python ', 'IA', 'PYTHON', ' ia ', 'Datos']), ['Python', 'IA', 'Datos'])
    def test_lista_vacia(self):
        self.assertEqual(limpiar_etiquetas([]), [])
    def test_entrada_incorrecta(self):
        with self.assertRaises(TypeError):
            limpiar_etiquetas('Python')
    def test_elemento_incorrecto(self):
        with self.assertRaises(TypeError):
            limpiar_etiquetas(['A', 3], 1)
    def test_limite_incorrecto(self):
        for limite in (0, -1, True, 1.5):
            with self.subTest(limite=limite):
                with self.assertRaises(ValueError):
                    limpiar_etiquetas(['A'], limite)

Hay diez métodos de prueba. Las comprobaciones del límite por defecto y del orden permiten detectar cambios que no afectarían a los casos más sencillos. El último agrupa varios límites incorrectos mediante subTest, de modo que puedas identificar qué valor falla. Estos tests no cubren todas las cadenas Unicode posibles ni sustituyen a las pruebas de la aplicación donde integrarás la función.

5. Ejecuta las pruebas desde la carpeta correcta

Guarda los dos archivos y abre la terminal en la carpeta que los contiene. Si está en otra ubicación, utiliza cd seguido de su ruta entre comillas. Ejecuta:

python -m unittest -v test_etiquetas

Si tu intérprete se llama python3 o py, sustituye solamente python por ese comando. La opción -v muestra el detalle. El resultado esperado, si ambos archivos se han copiado correctamente, es un informe de diez pruebas que termina en OK; el tiempo depende de tu equipo.

Comprobación del ejemplo: esta función y la batería mostrada se han ejecutado con Python 3.12.3: las diez pruebas terminaron en OK. Al introducir el cambio deliberado de la sección siguiente, tres pruebas detectaron el fallo. Esto comprueba los casos incluidos, no todos los usos posibles; vuelve a ejecutar la batería en tu equipo antes de integrar el código en un proyecto.

Cómo interpretar los problemas habituales

  • El comando Python no se reconoce: no has llegado a los tests. Comprueba la instalación y cuál de los comandos anteriores funciona.
  • No module named etiquetas: comprueba que los dos archivos están en la misma carpeta y que ejecutas desde ella. Revisa que no se llamen etiquetas.py.txt.
  • Ran 0 tests: no es una aprobación. Revisa el nombre del archivo, la clase heredada de unittest.TestCase y los métodos que empiezan por test_.
  • FAIL: una comprobación no coincide con el contrato. Lee la entrada y el resultado esperado antes de cambiar nada.
  • ERROR: la prueba produjo una excepción no contemplada. Busca la última línea del mensaje y el archivo y línea que la originaron.

6. Haz que una prueba detecte un error deliberado

Un informe verde solo indica que han pasado los casos ejecutados. Para comprobar una protección concreta, guarda una copia del archivo y cambia temporalmente clave = limpia.casefold() por clave = limpia. Vuelve a ejecutar el mismo comando: ahora la prueba de duplicados debería fallar porque «Python» y «PYTHON» dejan de compararse igual. Restaura después la línea original y repite la ejecución.

Es un cambio deliberado para aprender a interpretar un fallo, no una prueba exhaustiva de calidad. Si el informe permanece verde tras ese cambio, comprueba que guardaste el archivo, que ejecutas en la carpeta correcta y que no eliminaste la prueba.

7. Corrige con ayuda de la IA sin borrar el problema

Si un caso falla, pega únicamente la función, la prueba afectada, las reglas relevantes y el mensaje de error, sin contraseñas ni datos privados. Puedes pedir:

Diagnostica este fallo. Determina primero si contradice el contrato la implementación o la expectativa del test. Propón el cambio mínimo y explica por qué. No elimines, desactives ni debilites la prueba para obtener OK. Indica qué tests debo volver a ejecutar y qué limitación sigue sin cubrirse.

Después revisa el cambio y ejecuta la batería completa. Para usar este método con otra función, conserva la secuencia: escribir reglas, acordar resultados, generar pruebas, ejecutarlas y comprobar que detectan al menos un error relevante. Añade casos reales cuando aparezcan problemas nuevos; no des por terminado el trabajo porque el asistente diga que el código está bien.

Fuentes consultadas