Estrategia de pruebas
Una aplicación de Archestack se prueba por capas, desde el editor que señala un error mientras escribes hasta el pipeline que no despliega mientras falle una prueba. Las propias pruebas forman parte de la aplicación: viven en sus paquetes, viajan con ella a cada espacio de trabajo y se ejecutan contra una base de datos sandbox propia, así que una prueba nunca lee ni cambia los datos reales de nadie.
Cinco capas
| Capa | Qué detecta | Cuándo se ejecuta |
|---|---|---|
| El editor | Código C# y de páginas que no compila, una columna o una business entity que no existe, un script module llamado con un argumento incorrecto | Mientras escribes |
| Simulaciones | Un script o un business event que hace lo que no debe, probado antes de guardarlo | Mientras escribes un script |
| Casos de prueba | El comportamiento: la regla que impone un business event, lo que devuelve un script module, lo que lee una business entity | Con cada cambio, y antes de cada despliegue |
| Comprobaciones del esquema | Un cambio de tabla que pierde datos, o que haría que un script tipado dejara de compilar | Antes de cada migración y de cada despliegue |
| Suites programadas | Cualquier cosa que haya cambiado alrededor de la aplicación: otro paquete, una actualización, datos que una regla no esperaba | Cada noche, o con cualquier programación, en todos los entornos |
Las dos primeras no requieren trabajo: el editor comprueba contra el mismo compilador y el mismo
modelo de datos con los que se ejecuta la aplicación, y el botón Test de un script
module y la simulación de un business event se ejecutan en modo de simulación, en el que las
escrituras con Db y Files se comprueban y se registran pero nunca se
hacen, y los correos y las notificaciones se registran pero no se envían. Todo lo demás que hace
un script por su cuenta es real: las llamadas HTTP, System.IO y todo lo que hace un
paquete NuGet, como una conexión a otra base de datos.
El resto de esta página trata de la
tercera capa, las pruebas que escribes, y de cómo las ejecutan las otras dos.
Casos de prueba: given, when, then
Un caso de prueba es una afirmación sobre la aplicación, en tres partes: las filas que hay que preparar (given), lo único que se ejecuta (when) y lo que tiene que cumplirse después (then). Los casos se agrupan en suites. Este, de la demo Service Planner, demuestra que el tablero de planificación marca un día como sobrecargado solo cuando las horas planificadas de un técnico superan su capacidad:
{
"name": "Week load flags a day over capacity",
"suite": "Service Planner",
"isEnabled": true,
"data": {
"description": "A day is overbooked only when its planned hours go over the technician's capacity.",
"given": [
{ "table": "service_technician", "rows": [
{ "name": "Ana Peeters", "daily_capacity_hours": 8 },
{ "name": "Bram Maes", "daily_capacity_hours": 8 }
] },
{ "table": "service_job", "rows": [
{ "title": "Heat pump install", "technician_id": 1, "planned_date": "2026-09-23", "estimated_hours": 5, "status": "Planned" },
{ "title": "Boiler service", "technician_id": 1, "planned_date": "2026-09-23", "estimated_hours": 4, "status": "Planned" },
{ "title": "Commissioning", "technician_id": 2, "planned_date": "2026-09-23", "estimated_hours": 8, "status": "Planned" }
] }
],
"when": { "kind": "ScriptModule", "name": "GetPlannerWeek", "parameters": { "week_start": "2026-09-21" } },
"then": [
{ "subject": "Result", "operator": "Succeeds" },
{ "subject": "Result", "operator": "Equals", "path": "technicians[0].days[2].overbooked", "expected": "true" },
{ "subject": "Result", "operator": "Equals", "path": "technicians[1].days[2].overbooked", "expected": "false" }
]
}
} Given
Las filas que necesita el caso, tabla por tabla, escritas de arriba abajo en un sandbox vacío. Las
filas reciben los ids 1, 2, 3 en el orden en que se escriben, que es a lo que apunta la clave
foránea de un fixture posterior: arriba, el technician_id 1 es Ana. Así que una tabla
a la que apunta otro fixture va primero, y una clave que genera la base de datos se omite, igual
que las columnas de auditoría y cualquier columna cuyo valor por defecto sirva. En el builder,
elegir una tabla rellena filas de ejemplo a partir de los nombres y los tipos de sus columnas, y
una clave foránea es un selector sobre las filas que escriben los fixtures de encima.
When
Exactamente un objetivo, identificado por su nombre, nunca por un id:
- Script module: ejecuta un módulo con los parámetros indicados.
- Business entity: vuelve a leer una entidad, filtrada si se quiere, para comprobar lo que mostraría una página.
- Business event: dispara un trigger sobre una fila, en el momento indicado (BeforeCreate, AfterUpdate, etc.), igual que lo haría un guardado.
- Script: C# libre con todo lo que tiene un script module, para un caso que tiene que hacer varias cosas antes de poder comprobar la afirmación.
Then
Cada comprobación es un sujeto, un operador y normalmente un valor esperado. Los sujetos son
Result (lo que devolvió el objetivo), Rows (filas que se leen de una tabla
después), Output (lo que registró el objetivo), Error, Duration y
Code. Los operadores son Equals, NotEquals, Contains, NotContains, GreaterThan, LessThan,
IsNull, IsNotNull, Matches (una expresión regular), RowCount, Succeeds y Fails. Una ruta como
technicians[0].days[2].overbooked entra en un resultado, y una ruta que no lleva a
ninguna parte hace fallar la comprobación e indica dónde se detuvo.
Probar que algo se rechaza
Muchas de las reglas de una aplicación dicen que no: un business event rechaza un guardado que rompería algo. El caso para una regla así intenta el guardado y comprueba que se rechazó, por el motivo correcto, y que no se escribió nada:
// A zero estimate is refused.csx: the target, a save the business event must stop
await Db.CreateAsync("service_job", new { title = "Check radiator valves", estimated_hours = 0 });
return "saved"; "then": [
{ "subject": "Result", "operator": "Fails" },
{ "subject": "Error", "operator": "Contains", "expected": "Estimated hours must be more than zero" },
{ "subject": "Rows", "operator": "RowCount", "table": "service_job", "expected": "0" }
] La segunda comprobación es la que importa. Fails por sí sola pasa con cualquier error, incluida una columna mal escrita, que es la forma más habitual en que una prueba en rojo deja de probar nada sin que nadie lo note. Ata el fallo a su mensaje.
Comprobaciones de código
Una comprobación que no se puede expresar con un sujeto y un operador es una
comprobación de código: C# que se ejecuta después del objetivo en el mismo
sandbox, con todo lo que tiene un script module, incluidos los conjuntos tipados sobre
Db. Result, Output, Error,
DurationMs y Failed contienen el resultado del objetivo, y
Assert dice qué esperaba y qué encontró cuando una comprobación falla (Equal,
NotEqual, True, False, Null, NotNull, Contains, Count y Fail). La comprobación falla cuando lanza
una excepción, cuando falla un Assert o cuando devuelve false.
// Planning a job marks it Planned.then.1.csx: a check one subject and one operator cannot say
var job = await Db.ServiceJob.SingleAsync(j => j.Title == "Boiler service");
Assert.Equal("Planned", job.Status);
Assert.NotNull(job.PlannedDate, "a planned job has a date");
var sameDay = await Db.ServiceJob
.Where(j => j.TechnicianId == job.TechnicianId && j.PlannedDate == job.PlannedDate)
.SumAsync(j => j.EstimatedHours);
Assert.True(sameDay <= 8, $"the day holds {sameDay} hours");
Recurre a una cuando una comprobación necesita varias filas a la vez, cálculos sobre ellas o una
comparación entre dos tablas. En un repositorio, cada comprobación de código es un archivo propio,
<Case>.then.<n>.csx, que se edita con las mismas funciones de C# que
cualquier script.
El sandbox
Una prueba nunca toca los datos del espacio de trabajo. Una ejecución redirige la base de datos con los datos a un sandbox, una base de datos aparte que se crea cuando hace falta con la forma de la real, y todas sus tablas se vacían antes de cada caso, así que las únicas filas que ve un caso son sus propios fixtures y lo que escribe su objetivo. Las definiciones siguen viniendo del espacio de trabajo, así que una prueba ejercita las business entities, los business events y los scripts que están a punto de publicarse. Cada espacio de trabajo tiene cuatro sandboxes, así que pueden ir cuatro ejecuciones a la vez; una quinta espera a que quede uno libre.
- Los correos y las notificaciones se registran, no se envían. El resultado de cada caso enumera lo que sus scripts habrían enviado por correo y a quién habrían notificado, así que un caso también puede comprobarlo.
- Los archivos se quedan como están. Las escrituras, movimientos y borrados con
Filesnunca llegan a la carpeta del workspace: la ejecución los guarda para sí, así que leer un archivo recién escrito funciona. - Las llamadas salientes son reales. Todo lo demás que hace un script por su cuenta ocurre en cada ejecución: una petición HTTP, una conexión SMTP que abre,
System.IOy todo lo que hace un paquete NuGet, como una conexión a otra base de datos, escrituras incluidas. Deja las llamadas a otros sistemas fuera de lo que ejecutan las pruebas, o apúntalas a un endpoint de pruebas o a una base de datos de pruebas. - El registro de resultados es real. La ejecución de un caso guardado registra su resultado en el caso y en la suite y escribe una entrada en el Event Log. La ejecución de un borrador sin guardar, desde el botón Run del editor de casos o desde VS Code, no registra nada.
Dónde viven las pruebas
Una prueba pertenece al paquete que prueba. Viaja con ese paquete en una exportación, una
importación o el Module Store, así que un módulo llega a un sitio nuevo con la demostración de que
sigue funcionando, y todo lo que nombra (el script module, la business entity, el business event)
lo nombra por su nombre, así que apunta a lo correcto en cualquier espacio de trabajo. En un
repositorio, las pruebas de un paquete son archivos: tests/<suite>/suite.json,
un archivo JSON por caso bajo cases/ y un .csx junto a un caso para un
objetivo Script o una comprobación de código. Se revisan y se fusionan como el código que prueban.
Ejecutar las pruebas
- En el builder, la página Test Suite enumera las suites y sus casos, y ejecuta un caso, una suite o todo, con lo esperado frente a lo real de cada comprobación fallida. Run, en el editor de casos, prueba el caso antes de guardarlo.
- En VS Code, Run Tests ejecuta un caso, una suite, un paquete o todos los paquetes contra el proyecto, cuatro casos a la vez, y muestra cada resultado en el árbol y en la vista Testing. Consulta Pruebas en la guía de VS Code.
- Con una programación, una suite con un cron se ejecuta sola, en cualquier
entorno en el que esté instalada:
0 0 2 * * ?es todas las noches a las dos. Cada ejecución escribe una entrada en el Event Log con el detalle de cada comprobación, y su último resultado queda en la suite. - En el pipeline, las pruebas de todos los paquetes se ejecutan contra un Archestack desechable construido a partir del repositorio antes de desplegar nada, y un solo fallo detiene el despliegue. Consulta Estrategia de despliegue.
- Desde un asistente de IA, el MCP Server le da a un modelo conectado la misma guía de pruebas y las herramientas para escribir un caso, ejecutarlo y corregirlo hasta que pase.
Leer un resultado
| Resultado | Significa |
|---|---|
| Passed | Todas las comprobaciones se cumplieron. |
| Failed | El objetivo se ejecutó y una comprobación no se cumplió. Cada comprobación fallida dice qué esperaba y qué encontró. |
| Error | El caso no llegó a sus comprobaciones: un fixture no se pudo insertar, un objetivo tiene un nombre incorrecto, o el objetivo lanzó una excepción cuando el caso no lo esperaba. Lee primero el error. |
| Skipped | El caso o su suite está desactivado. |
Qué probar primero
- Los business events que protegen los datos. Cada regla que rechaza un guardado o un borrado tiene un caso que se rechaza y un caso que se permite, para que la regla no falte ni sea demasiado estricta.
- Los script modules que calculan. Con unas pocas filas, comprueba los números que devuelve el módulo, y los límites: un día vacío, un día lleno justo, un día que se pasa.
- Las lecturas de las que depende la aplicación. Un objetivo Business entity con un filtro, y un RowCount, demuestran que una página muestra las filas que debe y ninguna que no deba.
- Flujos de varios pasos. Un objetivo Script que hace lo que haría un usuario, y comprobaciones de código sobre todo lo que debería haber venido después.
Pruebas que siguen siendo útiles
- Un caso, una afirmación. Un caso que comprueba diez cosas no dice cuál de las diez se rompió.
- Nombra el caso por la regla. "A zero estimate is refused" se lee como una especificación en la lista de resultados.
- Comprueba el comportamiento, no el fixture. Contar las filas que acabas de insertar prueba el cargador de fixtures.
- Ata cada fallo a su mensaje, como arriba.
- Mantén pequeños los fixtures. Solo las filas que necesita la afirmación, sin claves generadas.
- Mantén las pruebas junto al código. Un cambio y la prueba que lo demuestra van en el mismo paquete, y en la misma pull request.
Hacia dónde va esto a continuación
Archestack en VS Code explica cómo ejecutar pruebas desde el editor, Estrategia de despliegue el pipeline que las ejecuta antes de cada despliegue, y la referencia los business events y los script modules de los que tratan la mayoría de las pruebas.