Skip to content

Commit e36d2cb

Browse files
authored
docs: expand mutation testing chapter (#70)
Closes #27 Resumen de revisión diferida: - PR fusionado en modo autónomo autorizado. - Validaciones locales y check remoto rust en verde. - Sin dependencias, coautor ni estados reviewed o published.
1 parent 3633e12 commit e36d2cb

4 files changed

Lines changed: 104 additions & 0 deletions

File tree

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,7 @@ path = "examples/soluciones/contract_testing_nivel_2.rs"
106106
[[example]]
107107
name = "contract_testing_nivel_3"
108108
path = "examples/soluciones/contract_testing_nivel_3.rs"
109+
110+
[[example]]
111+
name = "mutation_testing"
112+
path = "examples/mutation_testing.rs"

diagrams/07-mutation-testing.mmd

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
flowchart TD
2+
A[Regla observable] --> B[Crear mutante pequeño]
3+
B --> C[Ejecutar suite]
4+
C --> D{¿La suite falla?}
5+
D -->|| E[Mutante muerto]
6+
D -->|No| F{¿Es equivalente?}
7+
F -->|| G[Documentar equivalencia]
8+
F -->|No| H[Investigar hueco]
9+
H --> I[Agregar aserción de comportamiento]

docs/07-mutation-testing.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,69 @@ representa una diferencia observable.
4545
El modelo describirá el tipo de mutación, su resultado y los riesgos de
4646
interpretar la supervivencia sin contexto.
4747

48+
## Teoría
49+
50+
Un mutante muerto da evidencia de que la suite distingue un cambio relevante.
51+
Uno que sobrevive inicia una investigación: quizá falta una aserción de
52+
comportamiento, quizá solo se ejecutó la línea o quizá el mutante es equivalente
53+
y no cambia lo que el consumidor puede observar.
54+
55+
La práctica sana no es escribir un test por cada superviviente. Es clasificar
56+
el resultado, decidir si la regla importa y, solo entonces, agregar una prueba
57+
que explique el comportamiento faltante.
58+
59+
## Diagrama
60+
61+
```mermaid
62+
flowchart TD
63+
A[Regla observable] --> B[Crear mutante pequeño]
64+
B --> C[Ejecutar suite]
65+
C --> D{¿La suite falla?}
66+
D -->|Sí| E[Mutante muerto]
67+
D -->|No| F{¿Es equivalente?}
68+
F -->|Sí| G[Documentar equivalencia]
69+
F -->|No| H[Investigar hueco]
70+
H --> I[Agregar aserción de comportamiento]
71+
```
72+
73+
El archivo fuente vive en `diagrams/07-mutation-testing.mmd`.
74+
75+
## Complejidad
76+
77+
El costo está en diagnosticar supervivientes. Mutar demasiadas reglas sin
78+
contexto produce una lista larga y poco accionable. Conviene empezar por reglas
79+
de negocio, condiciones y bordes cuyo cambio tendría una consecuencia clara.
80+
81+
## Implementación
82+
83+
`MutationDecision` en `src/mutation_testing.rs` representa la regla mutada, el
84+
tipo de mutación, el resultado y huecos como cobertura sin aserción o una
85+
equivalencia no investigada.
86+
87+
## Pruebas
88+
89+
El módulo incluye pruebas unitarias, un consumidor externo y un doctest para
90+
verificar su API pública.
91+
92+
## Benchmarks
93+
94+
No hay benchmark propio. El modelo no mide el costo de una herramienta real de
95+
mutación; `cargo bench --all-targets` mantiene la verificación de ruta.
96+
97+
## Ejemplos
98+
99+
```bash
100+
cargo run --example mutation_testing
101+
```
102+
103+
## Ejercicios
104+
105+
Los ejercicios y soluciones graduadas se agregan al cerrar el capítulo.
106+
107+
## Referencias internas
108+
109+
- RFC-0001 §13: Rust como núcleo técnico.
110+
- RFC-0001 §14: anatomía de cursos y capítulos.
111+
- RFC-0001 §20: revisión humana diferida.
112+
48113
No está marcado como `reviewed` ni `published`.

examples/mutation_testing.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use rust_testing::mutation_testing::{
2+
MutationDecision, MutationGap, MutationKind, MutationOutcome,
3+
};
4+
fn main() -> Result<(), rust_testing::mutation_testing::MutationError> {
5+
for d in [
6+
MutationDecision::new(
7+
"rechaza saldo negativo",
8+
MutationKind::Condition,
9+
MutationOutcome::Killed,
10+
)?,
11+
MutationDecision::new(
12+
"limita descuento",
13+
MutationKind::Boundary,
14+
MutationOutcome::Survived,
15+
)?,
16+
MutationDecision::new(
17+
"devuelve total",
18+
MutationKind::ReturnValue,
19+
MutationOutcome::Equivalent,
20+
)?
21+
.with_gap(MutationGap::UninvestigatedEquivalent),
22+
] {
23+
println!("{} => {:?}, señal: {:?}", d.rule(), d.outcome(), d.signal());
24+
}
25+
Ok(())
26+
}

0 commit comments

Comments
 (0)