7. Convenciones para nombrar pruebas, carpetas, datos y utilidades

7.1 Objetivo del tema

Una suite automatizada no solo debe funcionar: también debe poder leerse, mantenerse y diagnosticarse rápidamente cuando falla. Para eso, los nombres son fundamentales.

En este tema definiremos convenciones para nombrar archivos de prueba, funciones de prueba, carpetas, datos y helpers. El objetivo es que cada nombre explique con claridad qué se está verificando y dónde debe ubicarse cada elemento.

Objetivo práctico: aplicar convenciones de nombres para que la suite sea fácil de recorrer, ejecutar y mantener.

7.2 Por qué importan los nombres

Cuando una prueba falla, el nombre es una de las primeras pistas. Un nombre como test_1 no ayuda a entender el problema. En cambio, test_calcular_total_aplica_descuento_al_cliente_frecuente comunica mucho más.

Buenos nombres ayudan a:

  • Encontrar pruebas relacionadas con una funcionalidad.
  • Entender qué comportamiento falló.
  • Evitar duplicar pruebas existentes.
  • Separar datos, helpers y casos de prueba.
  • Mantener una estructura consistente a medida que la suite crece.

7.3 Convención para archivos de prueba

En este curso usaremos archivos que comienzan con test_:

tests/
|-- test_calculadora.py
|-- test_textos.py
`-- test_usuarios.py

Esta convención coincide con la configuración que definimos en pytest.ini:

python_files = test_*.py

Si un archivo no sigue esta convención, pytest podría no detectarlo automáticamente.

7.4 Convención para funciones de prueba

Las funciones de prueba también deben comenzar con test_:

def test_sumar_devuelve_la_suma_de_dos_numeros():
    assert sumar(2, 3) == 5

Evita nombres demasiado genéricos:

def test_ok():
    assert sumar(2, 3) == 5

El primer nombre explica el comportamiento. El segundo solo dice que algo debería estar bien, pero no indica qué.

7.5 Formato recomendado para nombres de pruebas

Usaremos este formato como guía:

test_funcion_o_comportamiento_condicion_resultado_esperado

Ejemplos:

def test_dividir_con_divisor_cero_lanza_value_error():
    ...


def test_normalizar_texto_con_espacios_externos_devuelve_texto_limpio():
    ...


def test_crear_nombre_usuario_con_mayusculas_devuelve_usuario_en_minusculas():
    ...

No todos los nombres necesitan tener todas las partes, pero sí deben comunicar la intención principal.

7.6 Nombres orientados al comportamiento

Una buena prueba describe una conducta observable. Por eso es mejor nombrar la prueba por lo que verifica, no por cómo está implementado el código.

Menos claro:

def test_if_descuento():
    ...

Más claro:

def test_calcular_precio_final_con_descuento_devuelve_precio_reducido():
    ...

El segundo nombre permite entender la regla incluso sin abrir el código de la prueba.

7.7 Nombres para casos de error

Cuando la prueba espera una excepción, conviene indicarlo en el nombre:

def test_dividir_con_divisor_cero_lanza_value_error():
    with pytest.raises(ValueError):
        dividir(10, 0)

También podríamos usar palabras como rechaza, invalido o error si hacen el nombre más natural:

def test_crear_nombre_usuario_rechaza_nombre_vacio():
    ...

7.8 Evitar nombres demasiado largos

Los nombres descriptivos son buenos, pero tampoco deben convertirse en párrafos. Si un nombre se vuelve demasiado largo, tal vez la prueba verifica demasiadas cosas.

Ejemplo excesivo:

def test_calcular_precio_final_cuando_el_precio_es_cien_y_el_descuento_es_diez_entonces_el_resultado_debe_ser_noventa():
    ...

Versión más práctica:

def test_calcular_precio_final_con_descuento_devuelve_precio_reducido():
    ...

7.9 Nombres para carpetas

Las carpetas deben tener nombres cortos, en minúsculas y relacionados con su responsabilidad:

tests/
|-- data/
|-- helpers/
|-- unit/
`-- integration/

Evita carpetas con nombres ambiguos:

tests/
|-- cosas/
|-- varios/
`-- pruebas_nuevas/

Una carpeta debe responder claramente qué tipo de contenido contiene.

7.10 Nombres para datos de prueba

Los archivos de datos deben indicar qué contienen y para qué caso se usan:

tests/data/
|-- usuarios_validos.json
|-- usuarios_invalidos.json
|-- productos_con_descuento.csv
`-- mensajes_de_error.txt

Evita nombres como datos1.json, archivo.csv o prueba.txt. Esos nombres obligan a abrir el archivo para saber si sirve.

7.11 Nombres para helpers

Los helpers deben expresar qué ayudan a construir o verificar:

tests/helpers/
|-- usuarios_helper.py
|-- textos_helper.py
`-- archivos_helper.py

Dentro de un helper, usa nombres de funciones orientados a la tarea:

def crear_usuario_valido():
    ...


def crear_usuario_sin_email():
    ...


def leer_json_de_prueba(nombre_archivo):
    ...

7.12 Nombres para fixtures

Las fixtures deben nombrarse por el dato o recurso que entregan, no por el mecanismo interno que usan.

Menos claro:

def fixture_1():
    ...

Más claro:

def usuario_valido():
    ...


def carpeta_temporal_con_archivos():
    ...

Veremos fixtures en profundidad más adelante, pero conviene adoptar desde ahora nombres que expliquen su propósito.

7.13 Renombrar una prueba poco clara

Supongamos que tenemos esta prueba:

def test_texto():
    assert normalizar_texto("  PYTHON  ") == "python"

Funciona, pero el nombre no comunica lo suficiente. Podemos mejorarla así:

def test_normalizar_texto_con_espacios_y_mayusculas_devuelve_texto_limpio():
    assert normalizar_texto("  PYTHON  ") == "python"

Si falla, el nombre ya indica qué comportamiento dejó de cumplirse.

7.14 Usar nombres consistentes con los marcadores

Si una prueba está marcada como config, su nombre también debería reflejar que se relaciona con configuración:

import pytest

from app.config import obtener_timeout


@pytest.mark.config
def test_config_obtener_timeout_devuelve_valor_definido_en_env():
    assert obtener_timeout() == 5

No es obligatorio repetir siempre el marcador en el nombre, pero puede ser útil cuando el archivo contiene pruebas de distintos tipos.

7.15 Buscar pruebas por nombre

Una ventaja de nombres claros es que podemos seleccionar pruebas con -k:

python -m pytest -k usuario

Ese comando ejecuta pruebas cuyo nombre contiene usuario. También podemos combinar palabras:

python -m pytest -k "usuario and invalido"

Esta forma de selección funciona mucho mejor si los nombres son descriptivos.

7.16 Aplicar convenciones al proyecto actual

Revisa los archivos creados hasta ahora y ajusta los nombres que sean demasiado generales. Por ejemplo:

  • test_sumar puede cambiarse a test_sumar_devuelve_la_suma_de_dos_numeros.
  • test_dividir_error puede cambiarse a test_dividir_con_divisor_cero_lanza_value_error.
  • datos.json puede cambiarse a usuarios_validos.json si contiene usuarios válidos.
  • helper.py puede cambiarse a usuarios_helper.py o textos_helper.py.

7.17 Ejecutar la suite después de renombrar

Cada vez que renombres archivos o funciones de prueba, ejecuta la suite completa:

python -m pytest

Esto confirma que pytest sigue detectando las pruebas y que los imports no se rompieron.

7.18 Crear una guía de nombres en el README

Agrega una sección breve al README.md del proyecto:

## Convenciones de nombres

- Los archivos de prueba comienzan con test_.
- Las funciones de prueba comienzan con test_.
- Las pruebas deben describir comportamiento, condición y resultado esperado.
- Los datos de prueba se guardan en tests/data.
- Los helpers reutilizables se guardan en tests/helpers.
- No usar nombres genéricos como test_1, datos.json o helper.py.

Una guía corta ayuda a mantener consistencia cuando el proyecto crece.

7.19 Problemas frecuentes

  • pytest no encuentra una prueba: revisa que el archivo y la función comiencen con test_.
  • Un nombre es demasiado largo: verifica si la prueba debería dividirse en casos más pequeños.
  • No sabes dónde ubicar un helper: colócalo en tests/helpers si solo lo usan las pruebas.
  • No sabes dónde ubicar datos: usa tests/data para datos pequeños y controlados.
  • Hay nombres mezclados en español e inglés: elige un idioma para el proyecto y mantén consistencia.

7.20 Ejercicio práctico

Crea el módulo app/cupones.py con una función validar_cupon. La función debe devolver True si el cupón tiene el texto DESC10 y False en cualquier otro caso.

Luego crea tests/test_cupones.py con nombres de prueba descriptivos para estos casos:

  • Cupón válido.
  • Cupón inválido.
  • Cupón válido escrito en minúsculas.
  • Cupón con espacios al comienzo o al final.

7.21 Solución propuesta

Archivo app/cupones.py:

def validar_cupon(cupon):
    return cupon.strip().upper() == "DESC10"

Archivo tests/test_cupones.py:

from app.cupones import validar_cupon


def test_validar_cupon_con_codigo_correcto_devuelve_true():
    assert validar_cupon("DESC10") is True


def test_validar_cupon_con_codigo_incorrecto_devuelve_false():
    assert validar_cupon("DESC20") is False


def test_validar_cupon_con_codigo_en_minusculas_devuelve_true():
    assert validar_cupon("desc10") is True


def test_validar_cupon_con_espacios_externos_devuelve_true():
    assert validar_cupon("  DESC10  ") is True

Ejecuta:

python -m pytest tests/test_cupones.py

7.22 Lista de verificación

Antes de continuar con el próximo tema, verifica lo siguiente:

  • Los archivos de prueba comienzan con test_.
  • Las funciones de prueba comienzan con test_.
  • Los nombres describen comportamiento y resultado esperado.
  • Las carpetas tienen nombres claros y en minúsculas.
  • Los datos de prueba no usan nombres genéricos.
  • Los helpers indican qué ayudan a construir o verificar.
  • La suite completa se ejecuta con python -m pytest después de renombrar.

7.23 Conclusión

En este tema definimos convenciones para nombrar pruebas, carpetas, datos y utilidades. Aunque parezca un detalle menor, los nombres influyen directamente en la mantenibilidad de una suite automatizada.

Una prueba con buen nombre funciona como documentación ejecutable. En el próximo tema veremos cómo automatizar la ejecución de una suite completa desde la terminal usando los criterios y comandos que ya preparamos.