A medida que un proyecto crece, también crece la cantidad de pruebas. Si los archivos de prueba no están bien organizados, la suite se vuelve difícil de navegar, ejecutar y mantener.
Una buena organización permite encontrar rápidamente las pruebas de una unidad, entender qué parte del sistema cubren y ejecutar grupos de pruebas según la necesidad.
En este tema veremos criterios generales para organizar archivos y suites de pruebas unitarias, sin depender de un lenguaje específico.
Una suite de pruebas es un conjunto de pruebas que se ejecutan juntas. Puede incluir todas las pruebas del proyecto o solo un subconjunto.
Ejemplos de suites:
En pruebas unitarias, buscamos que la suite sea rápida, clara y confiable.
Una estructura de pruebas debería ayudar a:
Hay dos estilos comunes para ubicar pruebas:
| Estilo | Descripción | Ventaja |
|---|---|---|
| Pruebas junto al código | El archivo de prueba se coloca cerca del archivo probado. | Es fácil ver código y prueba juntos. |
| Carpeta separada de pruebas | Las pruebas viven en una carpeta como tests o test. |
Se separa claramente código productivo y código de prueba. |
No hay una única respuesta correcta. Lo importante es que el proyecto sea consistente.
Una estructura típica puede ser:
proyecto/
src/
calculadora.py
descuentos.py
tests/
test_calculadora.py
test_descuentos.py
El archivo test_descuentos.py contiene pruebas para descuentos.py. La relación es fácil de deducir por el nombre.
Otro estilo es colocar la prueba junto a la unidad:
proyecto/
src/
descuentos.py
descuentos_test.py
calculadora.py
calculadora_test.py
Este estilo se usa bastante en algunos ecosistemas. Permite localizar la prueba cerca del archivo probado, aunque mezcla archivos de producción y prueba en la misma carpeta.
Los frameworks suelen detectar pruebas por convenciones de nombres. Algunos ejemplos comunes:
test_descuentos.py o descuentos_test.py.CalculadoraTest.descuentos.test.js o descuentos.spec.js.Más allá del lenguaje, conviene que el nombre del archivo indique claramente qué unidad o módulo se prueba.
Una práctica habitual es tener un archivo de prueba por módulo, clase o unidad importante.
src/
carrito.py
pedido.py
cliente.py
tests/
test_carrito.py
test_pedido.py
test_cliente.py
Esta correspondencia facilita encontrar pruebas. Si queremos revisar el comportamiento de pedido.py, sabemos dónde buscar.
Un archivo de prueba con cientos o miles de líneas puede volverse difícil de mantener. Si un módulo tiene muchas responsabilidades y muchas pruebas, quizá convenga dividirlo.
Posibles divisiones:
Si las pruebas de una unidad crecen demasiado, también puede ser señal de que la unidad productiva tiene demasiadas responsabilidades.
Dentro de un archivo, conviene agrupar pruebas relacionadas. Por ejemplo, las pruebas de descuentos pueden dividirse por tipo de cliente o por reglas de monto.
def test_cliente_comun_no_tiene_descuento():
assert obtener_descuento("comun") == 0
def test_cliente_vip_tiene_descuento_15():
assert obtener_descuento("vip") == 15
def test_cliente_empleado_tiene_descuento_20():
assert obtener_descuento("empleado") == 20
La cercanía entre estas pruebas ayuda a leer la regla completa.
Es importante no mezclar pruebas unitarias con pruebas de integración en la misma suite sin distinguirlas. Las unitarias deberían ser rápidas y con pocas dependencias; las de integración pueden necesitar base de datos, red o servicios.
Una estructura posible:
tests/
unit/
test_descuentos.py
test_validaciones.py
integration/
test_repositorio_usuarios.py
test_api_pedidos.py
Esta separación permite ejecutar solo unitarias durante el desarrollo y dejar integración para momentos específicos.
Si algunas pruebas tardan más, conviene identificarlas. Una suite unitaria lenta se ejecuta menos y pierde valor como retroalimentación rápida.
Las pruebas lentas suelen indicar que:
Si una prueba unitaria se vuelve lenta, conviene revisar si realmente es unitaria.
Las pruebas unitarias no deberían depender del orden de ejecución. Cada prueba debe preparar sus propios datos y poder ejecutarse de manera independiente.
Ejemplo riesgoso:
usuarios = []
def test_agregar_usuario():
usuarios.append("Ana")
assert len(usuarios) == 1
def test_lista_tiene_usuario():
assert "Ana" in usuarios
La segunda prueba depende de que la primera se haya ejecutado antes. Esto rompe la independencia y puede generar fallas difíciles de entender.
Durante el desarrollo, muchas veces queremos ejecutar solo las pruebas relacionadas con el cambio actual. Una buena organización facilita esto.
Ejemplos de ejecución selectiva:
La posibilidad de ejecutar subconjuntos acelera el ciclo de trabajo.
Los nombres de carpetas deben comunicar el tipo de prueba o el área del sistema.
tests/
unit/
integration/
e2e/
Otra opción es organizar por módulo:
tests/
pedidos/
usuarios/
pagos/
La elección depende del tamaño del proyecto, pero conviene evitar estructuras ambiguas como misc, varios o pruebas2.
Las pruebas pueden necesitar helpers, datos de ejemplo o pequeñas fábricas de objetos. Conviene ubicarlos de forma clara.
tests/
unit/
test_descuentos.py
test_carrito.py
helpers/
builders.py
datos.py
Los helpers deben seguir siendo simples. Si crecen demasiado, pueden convertirse en otra fuente de complejidad.
Para pruebas unitarias, normalmente no hace falta cargar archivos enormes de datos. Los datos pequeños y explícitos suelen ser mejores.
Si una prueba necesita un archivo grande, puede ser señal de que:
Los datos grandes pueden ser útiles en otros tipos de pruebas, pero no deberían ser la norma en pruebas unitarias.
| Situación | Organización recomendada |
|---|---|
| Proyecto pequeño | Carpeta tests con archivos por módulo. |
| Proyecto con varios tipos de prueba | Separar unit, integration y e2e. |
| Módulo con muchas reglas | Dividir pruebas por comportamiento o clase. |
| Preparación repetida | Crear helpers simples y visibles. |
| Pruebas lentas mezcladas con unitarias | Separarlas o marcarlas para ejecución aparte. |
Al organizar pruebas, revisa:
Organizar bien archivos y suites de pruebas es una inversión en mantenibilidad. Una estructura clara ayuda a que las pruebas crezcan sin volverse caóticas.
La mejor organización es la que permite encontrar pruebas, entender su propósito, ejecutarlas con facilidad y mantener separadas las responsabilidades de cada tipo de prueba.
En el próximo tema veremos el ciclo de ejecución: ejecutar, fallar, corregir y repetir.