Merge pull request 'Add detailed test flow documentation to backend tests README' (#246) from feature/testing into development

Reviewed-on: ADUANASOFT/anexo76#246
This commit is contained in:
2026-03-24 17:58:23 +00:00

View File

@@ -6,6 +6,130 @@
- `tests/integration/`: process API behavior and edge cases.
- `tests/unit/`: critical algorithms only (no trivial CRUD tests).
---
## Vista del flujo de tests (backend)
### Dónde vive todo
| Capa | Ruta | Rol |
|------|------|-----|
| Infra | [conftest.py](conftest.py) | DB en transacción + rollback, Celery eager, app mínima con router de process, overrides de DB/usuario, tareas import/export **inline** en la misma sesión |
| Datos | [fixtures/builders.py](fixtures/builders.py) | Catálogos, tenant/company, facturas import/export con líneas enlazadas |
| E2E | [e2e/test_inventory_flow_anexo24.py](e2e/test_inventory_flow_anexo24.py) | Flujo negocio completo import → export → saldos/descargas |
| Integración | [integration/test_import_process_api.py](integration/test_import_process_api.py), [integration/test_export_process_api.py](integration/test_export_process_api.py) | API HTTP + reglas por tipo de factura, saldo, doble proceso |
| Unit | [unit/invoices/test_balance_algorithm.py](unit/invoices/test_balance_algorithm.py), [unit/invoices/test_currency_conversion_imports.py](unit/invoices/test_currency_conversion_imports.py) | Algoritmos puros / subprocesos sin HTTP |
### Infraestructura (flujo común)
```mermaid
flowchart TB
subgraph fixtures [Fixtures conftest]
db[db_session: conexion + begin + Session]
roll[teardown: rollback + close]
celery[celery_eager autouse: memory broker]
app[app: FastAPI + process router]
client[TestClient]
end
db --> roll
celery --> app
db --> app
app --> client
subgraph inline [Monkeypatch rutas]
imp[process_invoice_task -> main_process import en db_session]
exp[process_export_invoice_task -> main_process export en db_session]
end
app --> inline
```
- **BD**: `TEST_DATABASE_URL` o `CORE_DATABASE_URL` o `settings.core_database_url`. Cada test corre dentro de una transacción; al terminar **no persiste** nada (rollback).
- **Celery**: sin Redis; `task_always_eager` para que el endpoint dispare lógica síncrona.
- **Seguridad en tests**: `validate_access_to_resource` se reemplaza por un stub que devuelve `tenant_id` del usuario fake.
### Builders: qué se construye antes de llamar a la API
Orden típico en casi todos los tests que tocan proceso:
1. `ensure_reference_data`: tipos de factura (`TEM`, `DEF`, `MEX`, `DONAC`) y régimen `A1` si no existen.
2. `ensure_tenant_company(tenant_id=1, company_id=1)`.
3. `create_business_catalogs`: proveedor/cliente/destinatario (con dirección idempotente vía `_ensure_client_provider_address`), agente aduanal, UoM, part number FA, tipo cambio, etc.
4. `create_import_invoice_with_line` / `create_export_invoice_with_line` según el caso.
### Parches al pipeline (import / export)
Los tests **no** ejecutan validadores pesados del proceso real; sustituyen funciones en `main_process` para aislar el comportamiento de saldos y API:
**Import** (varios tests): `pre_validators` devuelve la línea creada; se anulan reviews de clase, tipo de cambio, pesos, SISIMP, `_validate_lines`.
**Export**: análogo con `pre_validators` + reviews de clase, TC, asignación, cantidad vs peso, costo, series.
**Caso especial**`test_process_endpoint_prevents_double_processing_import` en [integration/test_export_process_api.py](integration/test_export_process_api.py): usa `_patch_import_pipeline_without_prevalidators` (sin parchear `pre_validators`) para que el **segundo** `POST /process` recorra el flujo real y dispare la validación de “ya procesado”.
### Mapa por archivo y edge cases
#### E2E — [e2e/test_inventory_flow_anexo24.py](e2e/test_inventory_flow_anexo24.py)
- **Flujo**: datos ref + tenant/company + catálogos → factura import `TEM` qty 10 → `POST .../process` → comprueba `BalanceMovement` tipo `ENTRY` → factura export ligada a import/línea qty 4 → `POST process` → comprueba `CONSUMPTION`, `DischargeHeader`, `DischargeDetail` con `movement_id`.
- **Edge implícito**: saldo neto por línea de import ≥ 0 y < 10 tras consumo parcial (no agota todo el inventario del escenario).
#### Integración import — [integration/test_import_process_api.py](integration/test_import_process_api.py)
| Test | Qué valida |
|------|------------|
| `test_process_import_endpoint_creates_balance_entries` | `TEM` + process → al menos un `ENTRY` por factura/línea |
| `test_process_import_def_does_not_create_balance_entries` | `DEF` + process → **ningún** movimiento de saldo (edge: tipo operación no genera entradas de balance) |
#### Integración export + doble proceso — [integration/test_export_process_api.py](integration/test_export_process_api.py)
| Test | Qué valida |
|------|------------|
| `_prepare_inventory` + `test_process_export_endpoint_consumes_existing_balances` | Tras import `TEM` qty 10, export qty 3 → existen `CONSUMPTION` |
| `test_process_export_prevents_negative_balance` | Export qty 99 vs saldo 10 → `ValidationException` y **cero** consumos para esa factura export |
| `test_process_endpoint_prevents_double_processing_import` | Segundo `POST` misma factura import → `ValidationException`; exactamente **un** `ENTRY` (no duplicar PEPS) |
#### Unit saldos / FIFO — [unit/invoices/test_balance_algorithm.py](unit/invoices/test_balance_algorithm.py)
- **`test_net_balance_accounts_for_returns_and_entry_void`**: `_net_balance_for_lot` con ENTRY, CONSUMPTION, RETURN, ENTRY_VOID (fórmula documentada en el docstring: 10 - 4 + 1 - 2 = 5).
- **`test_fifo_consumption_algorithm_uses_oldest_lots_first`**: `compare_balances` con dos `AvailableLot` (órdenes 1 y 2), demanda 6; parche `_resolve_import_uom` → PZA; comprueba consumo 3+3 y `quantity_used == 6`.
#### Unit IVA / moneda — [unit/invoices/test_currency_conversion_imports.py](unit/invoices/test_currency_conversion_imports.py)
- Tres monedas en `assign_values_iva_lines`: **FOREIGN (ME)**, **LOCAL (MN)**, **MANUAL (MC)** con `SimpleNamespace` (sin BD).
### Diagrama de flujo de negocio (E2E + integración export)
```mermaid
sequenceDiagram
participant T as Test
participant API as POST process
participant DB as Session PostgreSQL
T->>DB: seed ref + catalogs + import invoice
T->>API: process import
API->>DB: ENTRY movements
T->>DB: export invoice linked
T->>API: process export
alt qty OK
API->>DB: CONSUMPTION + discharges
else qty over balance
API-->>T: ValidationException
end
```
### Resumen de edge cases explícitos en la suite
- **Tipo factura import**: `TEM` genera saldo; `DEF` no.
- **Saldo insuficiente en export**: error y sin consumos.
- **Doble procesamiento import**: error en segundo POST y una sola entrada.
- **Neteo de movimientos**: retornos y anulaciones de entrada en el cálculo de saldo.
- **FIFO**: reparto entre lotes por `order_peps`.
- **Moneda / IVA**: tres modos de captura y conversión esperada.
### BD compartida / CI
Si `TEST_DATABASE_URL` apunta a una base con datos previos, los builders reutilizan filas existentes donde aplica (por ejemplo direcciones de clientes vía `_ensure_client_provider_address`). Para máximo aislamiento, usar una BD o esquema dedicado a tests.
---
## Prerequisites
- PostgreSQL test database available.