Skip to content

fix(test): aislar el almacén de cada clase de integración (TD-011) y cerrar TD-003 - #20

Merged
beyondnetPeru merged 1 commit into
mainfrom
fix/td011-aislar-suite-integracion
Aug 10, 2026
Merged

fix(test): aislar el almacén de cada clase de integración (TD-011) y cerrar TD-003#20
beyondnetPeru merged 1 commit into
mainfrom
fix/td011-aislar-suite-integracion

Conversation

@beyondnetPeru

Copy link
Copy Markdown
Contributor

Resuelve TD-011 y cierra TD-003. Con esto, de las cuatro entradas abiertas quedan dos, y ninguna de ellas es mía de resolver — ver el final.

TD-011 — la causa de los 133 fallos, con nombre y apellidos

La factoría registraba sus tres almacenes InMemory con nombres literales:

ReplaceDbContextWithInMemory<UmsPlatformDbContext>(services, "TestDb");
ReplaceDbContextWithInMemory<TenantProjectionDbContext>(services, "TestProjectionDb");
ReplaceDbContextWithInMemory<ReadModelDbContext>(services, "TestReadModelDb");

El proveedor InMemory de EF Core indexa cada almacén por su nombre dentro del proceso. Daba igual cuántas instancias de factoría hubiera: las 31 clases de la suite compartían exactamente los mismos tres almacenes. Una escritura en cualquiera se veía desde todas.

Eso es lo que convirtió una prueba nueva en 133 fallos en CI — y lo que hizo que pasara en local, en Debug y en Release: el orden de ejecución la escondía.

Arreglo: cada instancia sufija sus nombres con un GUID propio. Cada clase arranca de la misma semilla y no puede alcanzar a ninguna otra.

Coste: ~5% de reloj (4m30s → 4m46s), por sembrar una vez por clase en vez de una vez.

La prueba que rompió todo vuelve, a propósito

La reañado como centinela: ejercita leer-tras-escribir contra el inquilino sembrado. Si alguien restituye el almacén compartido, falla de inmediato en vez de corromper en silencio cien aserciones ajenas.

Lo que este PR no cubre

ContractTestWebApplicationFactory y PostgreSqlWebApplicationFactory usan el mismo patrón de nombre fijo. Ninguna da síntoma hoy —la de contrato es una sola colección, la de PostgreSQL se salta sin Docker— pero el riesgo es idéntico. Anotado en la entrada, sin tocar: cambiarlas sin síntoma ni cobertura que lo demuestre es mover algo que funciona.

TD-003 — no era deuda, ya estaba hecho

La entrada declaraba pendiente «migrar la caché a Redis sin cambiar IConfigurationProvider». Al ir a hacerlo, resulta que existe:

IConfigurationCache La abstracción que la entrada proponía introducir
RedisConfigurationCache 291 líneas, invalidación por Pub/Sub entre réplicas, cero NotImplementedException
InMemoryConfigurationCache El respaldo en proceso
DependencyInjection Elige entre ambas según Redis:Connection — y también REDIS_CONNECTION, la forma de Kubernetes, cuya omisión ya fue un bug encontrado y corregido
AvisoDeConfiguracionEntreReplicasTests Cubre la invalidación entre réplicas

Todas las mitigaciones que listaba como trabajo futuro están puestas. Lo que queda es aprovisionar Redis, que es infraestructura y no deuda de este repositorio.

Nadie releyó la entrada cuando el trabajo aterrizó. Un registro de deuda solo sirve si se cierra lo pagado; arrastrar un fantasma es la misma forma de fallo que ya mostró TD-002.

Verificación

  • Ums.Presentation.IntegrationTest314/316 (2 saltadas) en Release, con la centinela dentro
  • dotnet build — 0 errores

CI es el juez real aquí: los 133 fallos solo aparecieron allí.

🤖 Generated with Claude Code

…-011

La factoría registraba sus tres almacenes InMemory con nombres LITERALES —«TestDb»,
«TestProjectionDb», «TestReadModelDb»— y el proveedor InMemory de EF Core indexa por
nombre dentro del proceso. Daba igual cuántas instancias de factoría hubiera: las 31
clases de la suite compartían exactamente los mismos tres almacenes, así que una
escritura en cualquiera se veía desde todas.

Cada instancia sufija ahora sus nombres con un GUID propio. Cada clase arranca de la
misma semilla y no puede alcanzar a ninguna otra. Coste: ~5% de reloj (4m30s → 4m46s),
por sembrar una vez por clase en lugar de una vez.

La prueba que provocó los 133 fallos se REAÑADE a propósito, como centinela: ejercita
leer-tras-escribir contra el inquilino sembrado, de modo que si alguien restituye el
almacén compartido vuelve a fallar de inmediato en vez de corromper en silencio cien
aserciones ajenas.

No cubierto: ContractTestWebApplicationFactory y PostgreSqlWebApplicationFactory usan el
mismo patrón de nombre fijo. Ninguna da síntoma hoy —la de contrato es una sola colección
y la de PostgreSQL se salta sin Docker— pero el riesgo es idéntico y queda anotado.

## TD-003 se cierra: ya estaba implementado

La entrada declaraba pendiente «migrar la caché a Redis sin cambiar IConfigurationProvider».
Esa migración existe: RedisConfigurationCache son 291 líneas con invalidación por Pub/Sub
entre réplicas y sin un solo NotImplementedException, la abstracción IConfigurationCache
está en Ums.Application, el registro elige entre Redis y memoria según `Redis:Connection`
—leyendo también la forma de Kubernetes— y hay pruebas de invalidación entre réplicas.
Todas las mitigaciones que listaba como trabajo futuro están puestas. Lo que queda es
aprovisionar Redis, que es infraestructura, no deuda de este repositorio.

Nadie la releyó al aterrizar el trabajo. Un registro de deuda solo sirve si se cierra lo
pagado; arrastrar un fantasma es la misma forma de fallo que mostró TD-002.

Verificado: Integración 314/316 (2 saltadas) en Release con la centinela dentro;
build 0 errores.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
secondaryText = "Subtítulo de pruebas",
primaryButtonLabel = "Entrar",
footerText = "Pie de pruebas",
customDomain = (string?)null,
@beyondnetPeru
beyondnetPeru merged commit 0f090cc into main Aug 10, 2026
24 checks passed
@beyondnetPeru
beyondnetPeru deleted the fix/td011-aislar-suite-integracion branch August 10, 2026 20:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants