ADR-014: Test Structure OrganizationΒΆ
Estado: β Accepted Date: 2026-01-29 Deciders: Rodrigo RoldΓ‘n
ContextΒΆ
Testing puede organizarse de varias formas:
Flat structure: Todos los tests en un directorio
Mirror structure: Tests reflejan estructura de src/
Organized by type: unit/, integration/, e2e/
Reqivo necesita:
Unit tests para cada mΓ³dulo
Integration tests para flujos completos
Mapeo claro cΓ³digo β tests
DecisionΒΆ
Estructura organizada por tipo con mirror de src/:
tests/
βββ unit/ β Tests unitarios
β βββ __init__.py
β βββ test_version.py β src/reqivo/version.py
β βββ test_exceptions.py β src/reqivo/exceptions.py
β βββ test_utils.py β src/reqivo/utils/*
β βββ test_response.py β src/reqivo/client/response.py
β βββ test_request.py β src/reqivo/client/request.py
β βββ test_session.py β src/reqivo/client/session.py (pendiente)
β βββ test_websocket.py β src/reqivo/client/websocket.py (pendiente)
β βββ test_http_parser.py β src/reqivo/http/http11.py (pendiente)
β βββ test_headers.py β src/reqivo/http/headers.py (pendiente)
β βββ test_body.py β src/reqivo/http/body.py (pendiente)
β βββ test_connection.py β src/reqivo/transport/connection.py (pendiente)
β βββ test_connection_pool.py β src/reqivo/transport/connection_pool.py (pendiente)
β
βββ integration/ β Tests de integraciΓ³n
β βββ __init__.py
β βββ test_http_requests.py β GET/POST flows completos
β βββ test_session_cookies.py β Session + cookies + redirects
β βββ test_websocket_flow.py β WebSocket handshake + messages
β βββ test_connection_pooling.py β Pool reuse + concurrency
β βββ test_tls_connections.py β HTTPS + TLS
β βββ test_timeouts.py β Timeout scenarios
β
βββ e2e/ β Tests end-to-end (futuro)
β βββ test_real_servers.py β Tests contra httpbin, etc.
β
βββ utils/ β Test utilities
βββ __init__.py
βββ fixtures.py β Shared fixtures
βββ mock_server.py β Mock HTTP server
βββ assertions.py β Custom assertions
Principios:
Mirror source structure:
src/reqivo/client/response.pyβtests/unit/test_response.pyUn test file por cada source file
Naming convention:
Unit tests:
test_<module>.pyIntegration tests:
test_<feature>_flow.pyotest_<component>_integration.py
Test organization dentro del archivo:
# tests/unit/test_response.py class TestResponseInit: """Tests for Response.__init__()""" class TestResponseText: """Tests for Response.text()""" class TestResponseJson: """Tests for Response.json()""" class TestResponseStreaming: """Tests for Response.iter_*()"""
Fixture organization:
Fixtures comunes en
tests/utils/fixtures.pyFixtures especΓficas en conftest.py local
ConsequencesΒΆ
Positive β ΒΆ
Findability: FΓ‘cil encontrar tests para un mΓ³dulo
Completeness: Detectar mΓ³dulos sin tests
Separation: Unit vs integration claro
Scalability: Estructura crece con proyecto
Clear mapping: 1:1 entre source y test files
Negative βΒΆ
Duplicate structure: Dos Γ‘rboles de directorios (src + tests)
Renaming overhead: Renombrar mΓ³dulo requiere renombrar test
Large test files: MΓ³dulos grandes β test files grandes
MitigationsΒΆ
Split large tests: Dividir por funcionalidad si es muy grande
Shared utilities: Reutilizar fixtures y helpers
Clear docstrings: Documentar quΓ© testea cada clase/funciΓ³n
Test NamingΒΆ
Unit test:
def test_response_text_decodes_utf8():
"""Response.text() should decode UTF-8 body correctly."""
def test_response_json_raises_on_invalid_json():
"""Response.json() should raise ValueError on invalid JSON."""
Integration test:
def test_session_preserves_cookies_across_requests():
"""Session should send cookies from previous response."""
def test_connection_pool_reuses_connections():
"""Connection pool should reuse connections for same host."""
Current StatusΒΆ
Existentes:
β
tests/unit/test_version.pyβ
tests/unit/test_exceptions.pyβ
tests/unit/test_utils.pyβ
tests/unit/test_response.pyβ
tests/unit/test_request.py
Pendientes (segΓΊn ADR-014):
β
tests/unit/test_session.pyβ
tests/unit/test_websocket.pyβ
tests/unit/test_http_parser.pyβ
tests/unit/test_headers.pyβ
tests/unit/test_body.pyβ
tests/unit/test_connection.pyβ
tests/unit/test_connection_pool.pyβ
tests/unit/test_auth.pyβ
tests/integration/*(todos)
Alternatives ConsideredΒΆ
Flat structure: Rejected. DifΓcil escalar.
By feature: Rejected. Ambiguo quΓ© es una βfeatureβ.
Colocated tests: Rejected. Mezcla concerns.
ReferencesΒΆ
pytest documentation: Test layout
Python Packaging Guide