10. Convenciones de nombres para archivos, clases y métodos de prueba

10.1 Objetivo del tema

Las herramientas de testing descubren pruebas siguiendo convenciones. Si un archivo, una clase o un método no tiene el nombre esperado, puede ocurrir que la prueba exista, pero no se ejecute.

En este tema veremos cómo nombrar archivos, clases y métodos de prueba para que unittest los encuentre de forma automática.

Idea clave: una prueba que no se descubre no protege el proyecto, aunque su código esté escrito correctamente.

10.2 Crear una carpeta de práctica

Crea un proyecto nuevo:

mkdir nombres-pruebas-demo
cd nombres-pruebas-demo

Trabajaremos con una estructura simple para concentrarnos en las convenciones de nombres.

10.3 Crear el código a probar

Crea un archivo llamado calculadora.py:

def sumar(a, b):
    return a + b


def restar(a, b):
    return a - b


def multiplicar(a, b):
    return a * b


def dividir(a, b):
    if b == 0:
        raise ValueError("No se puede dividir por cero")
    return a / b

Este archivo tendrá pruebas correctas y ejemplos de nombres incorrectos para ver qué descubre unittest.

10.4 Regla para nombres de archivos

Por defecto, unittest descubre archivos cuyo nombre coincide con el patrón test*.py. Una convención muy usada es comenzar con test_:

test_calculadora.py

Estos nombres también serían descubiertos por el patrón por defecto:

testcalculadora.py
test_operaciones.py
test_pruebas_basicas.py

En este curso usaremos test_*.py porque es más legible.

10.5 Crear un archivo de pruebas correcto

Crea test_calculadora.py:

import unittest

from calculadora import dividir, multiplicar, restar, sumar


class TestCalculadora(unittest.TestCase):

    def test_sumar_dos_numeros(self):
        resultado = sumar(2, 3)

        self.assertEqual(resultado, 5)

    def test_restar_dos_numeros(self):
        resultado = restar(10, 4)

        self.assertEqual(resultado, 6)

El archivo comienza con test_, la clase comienza con Test y los métodos comienzan con test_.

10.6 Regla para nombres de clases

En unittest, las clases de prueba normalmente heredan de unittest.TestCase y se nombran comenzando con Test:

class TestCalculadora(unittest.TestCase):
    pass

El nombre de la clase debe explicar qué unidad o comportamiento agrupa. Por ejemplo:

class TestCalculadora(unittest.TestCase):
    pass


class TestValidacionesDeUsuario(unittest.TestCase):
    pass


class TestCarrito(unittest.TestCase):
    pass

10.7 Regla para nombres de métodos

Los métodos que deben ejecutarse como pruebas tienen que comenzar con test_:

def test_multiplicar_dos_numeros(self):
    resultado = multiplicar(3, 4)

    self.assertEqual(resultado, 12)

Si el método se llama multiplicar_dos_numeros, sin test_, unittest no lo ejecutará automáticamente.

10.8 Agregar más métodos correctos

Completa test_calculadora.py agregando estas pruebas dentro de la clase:

def test_multiplicar_dos_numeros(self):
    resultado = multiplicar(3, 4)

    self.assertEqual(resultado, 12)


def test_dividir_dos_numeros(self):
    resultado = dividir(10, 2)

    self.assertEqual(resultado, 5)


def test_dividir_por_cero_lanza_error(self):
    with self.assertRaises(ValueError):
        dividir(10, 0)

Cada nombre describe el comportamiento que se está verificando.

10.9 Ejecutar las pruebas descubiertas

Desde la carpeta del proyecto, ejecuta:

python -m unittest -v

La salida esperada será similar a:

test_dividir_dos_numeros ... ok
test_dividir_por_cero_lanza_error ... ok
test_multiplicar_dos_numeros ... ok
test_restar_dos_numeros ... ok
test_sumar_dos_numeros ... ok

----------------------------------------------------------------------
Ran 5 tests in 0.001s

OK

10.10 Archivo con nombre incorrecto

Ahora crea un archivo llamado prueba_calculadora.py:

import unittest

from calculadora import sumar


class TestNombreDeArchivo(unittest.TestCase):

    def test_sumar_en_archivo_mal_nombrandado(self):
        self.assertEqual(sumar(1, 1), 2)

El método está bien nombrado, pero el archivo no comienza con test. Por eso python -m unittest no lo descubrirá por defecto.

10.11 Ejecutar con patrón personalizado

Podemos indicar un patrón distinto para descubrir ese archivo:

python -m unittest discover -p "prueba_*.py"

Esto funciona, pero no conviene depender de patrones raros sin necesidad. Usar test_*.py evita confusiones.

10.12 Método con nombre incorrecto

Agrega este método dentro de TestCalculadora:

def sumar_sin_prefijo_test(self):
    resultado = sumar(5, 5)

    self.assertEqual(resultado, 10)

Este método no se ejecutará automáticamente porque no empieza con test_. La prueba parece existir, pero no forma parte de la suite descubierta.

10.13 Clase sin heredar de TestCase

Este ejemplo tampoco será tratado como una clase de pruebas por unittest:

class TestSinHerencia:

    def test_algo(self):
        assert sumar(1, 2) == 3

Aunque el nombre empieza con Test, la clase no hereda de unittest.TestCase. Para este curso mantendremos siempre esa herencia.

10.14 Nombres descriptivos

Un buen nombre de prueba describe el comportamiento esperado. Compara estos dos nombres:

def test_1(self):
    pass


def test_dividir_por_cero_lanza_error(self):
    pass

El segundo nombre permite entender qué regla se está probando sin abrir todo el cuerpo del método.

10.15 Evitar nombres demasiado generales

Estos nombres son válidos, pero poco informativos:

def test_funciona(self):
    pass


def test_calculo(self):
    pass


def test_error(self):
    pass

Conviene nombrar la condición y el resultado esperado: test_precio_negativo_lanza_error, test_usuario_mayor_de_edad_esta_activo o test_lista_vacia_devuelve_cero.

10.16 Tabla de convenciones

Elemento Convención recomendada Ejemplo
Archivo de prueba Comenzar con test_ test_calculadora.py
Clase de prueba Comenzar con Test y heredar de unittest.TestCase class TestCalculadora(unittest.TestCase)
Método de prueba Comenzar con test_ test_sumar_dos_numeros
Nombre descriptivo Indicar condición y resultado esperado test_dividir_por_cero_lanza_error

10.17 Archivo completo recomendado

El archivo test_calculadora.py debería quedar así:

import unittest

from calculadora import dividir, multiplicar, restar, sumar


class TestCalculadora(unittest.TestCase):

    def test_sumar_dos_numeros(self):
        resultado = sumar(2, 3)
        self.assertEqual(resultado, 5)

    def test_restar_dos_numeros(self):
        resultado = restar(10, 4)
        self.assertEqual(resultado, 6)

    def test_multiplicar_dos_numeros(self):
        resultado = multiplicar(3, 4)
        self.assertEqual(resultado, 12)

    def test_dividir_dos_numeros(self):
        resultado = dividir(10, 2)
        self.assertEqual(resultado, 5)

    def test_dividir_por_cero_lanza_error(self):
        with self.assertRaises(ValueError):
            dividir(10, 0)


if __name__ == "__main__":
    unittest.main()

10.18 Comprobar cuántas pruebas se ejecutaron

Después de ejecutar la suite, mira la línea Ran ... tests. Si esperabas cinco pruebas y aparece una cantidad menor, probablemente algún nombre no respeta la convención.

Ran 5 tests in 0.001s

Esta línea es una señal rápida para detectar pruebas que no fueron descubiertas.

10.19 Errores frecuentes

  • Nombrar el archivo como prueba_algo.py: no coincide con el patrón por defecto.
  • Olvidar el prefijo test_ en métodos: el método no se ejecuta.
  • No heredar de unittest.TestCase: la clase no se comporta como una clase de pruebas de unittest.
  • Usar nombres como test_1: son válidos, pero no explican la intención.
  • No revisar la cantidad de pruebas ejecutadas: puede ocultar pruebas no descubiertas.

10.20 Comandos usados en este tema

mkdir nombres-pruebas-demo
cd nombres-pruebas-demo
python -m unittest
python -m unittest -v
python -m unittest discover
python -m unittest discover -p "test_*.py"
python -m unittest discover -p "prueba_*.py"

10.21 Qué debes recordar de este tema

  • Los archivos de prueba deben coincidir con el patrón de descubrimiento.
  • Usar test_*.py es una convención clara y frecuente.
  • Las clases de prueba deben heredar de unittest.TestCase.
  • Los métodos de prueba deben empezar con test_.
  • Los nombres deben explicar el comportamiento probado.
  • La cantidad de pruebas ejecutadas ayuda a detectar problemas de descubrimiento.

10.22 Conclusión

En este tema vimos las convenciones de nombres que permiten a unittest descubrir pruebas automáticamente. Archivos, clases y métodos bien nombrados hacen que la suite sea más confiable y más fácil de leer.

En el próximo tema instalaremos pytest y realizaremos una primera ejecución con ese framework de pruebas.