tane/docs/design/testing.md
2026-07-07 13:20:00 +02:00

3.3 KiB

Tanemaki — Estrategia de pruebas (casi-TDD, sin depender de pruebas manuales)

Convención del proyecto. Objetivo: cada comportamiento cubierto por una prueba automática; las pruebas manuales son la excepción, no la red de seguridad.

Principio

Casi-TDD. Para lógica nueva: test primero (red → green → refactor). Como mínimo innegociable: ninguna rama se mergea sin tests que cubran lo nuevo. La "definición de hecho" de cada historia incluye sus tests; sin tests, no está hecha. CI en cada push bloquea si algo falla o baja la cobertura.

commons_core es Dart puro (sin Flutter) → la lógica difícil (CRDT, identidad/derivación, cifrado, backup, pledge/WoT) se hace con TDD cómodo y rápido.

La pirámide (Flutter/Dart)

  • Unit (dart test / flutter test): lógica pura — CRDT, Quantity, derivación de claves, serialización, repositorios. Rápidos; el grueso vive en commons_core.
  • Widget (flutter_test, pumpWidget): pantallas y componentes — interacción, progressive disclosure, i18n, accesibilidad (targets grandes).
  • Integration (integration_test + flutter test): app entera en emulador/dispositivo, con BD real cifrada (SQLCipher). Flujos e2e — esto es lo que sustituye a las pruebas manuales.
  • Golden (regresión visual): pantallas clave; vigila que la accesibilidad no se rompa.
  • Migration (Drift): drift_dev schema generate + validateDatabaseSchema por cada schemaVersion.

Tests que este proyecto necesita sí o sí

  • Cifrado en reposo: abrir el fichero de BD en crudo y afirmar que NO hay texto en claro (buscar una etiqueta conocida en los bytes y exigir ausencia). Regresión de seguridad clave para el "peor caso legal".
  • CRDT — convergencia: property-based — fusionar operaciones en cualquier orden converge al mismo estado (LWW, OR-Set, log append-only, tombstones).
  • Migraciones: cada versión migra desde la anterior y valida contra el esquema fresco.
  • Backup round-trip: exportar → borrar → importar → estado idéntico (y cifrado).
  • Identidad: derivación secp256k1 determinista desde la semilla (mismo input → misma clave) y unidireccional.
  • i18n: ninguna cadena hardcodeada (lint), y todas las locales con las mismas claves.

Lo difícil de automatizar (y cómo)

Cámara, keystore/biométrico, relays reales: abstraer tras interfaces y probar con fakes/mocks; dejar una capa fina de adaptadores de plataforma con un smoke test mínimo. Los integration tests en dispositivo cubren la integración real de la BD cifrada. Objetivo: manual ≈ 0.

CI y cobertura

  • CI en cada push/PR (Forgejo/Codeberg Actions o GitHub Actions): flutter analyze + unit + widget + integration en emulador + cobertura (lcov). Merge bloqueado si falla o baja la cobertura.
  • Objetivo de cobertura alto en commons_core (p.ej. ≥ 85%); la UI, con widget + golden.
  • Tests deterministas y rápidos: sin red real, reloj/UUID/HLC inyectables (para reproducibilidad).

Flujo de trabajo

Dominio (commons_core): test primero. UI: al menos un widget test por pantalla/flujo antes de darla por terminada, y un integration test por flujo crítico (alta de semilla → persiste cifrada → reabrir → sigue ahí). Regla dura repetida: sin tests, no se mergea.