Skip to content

Commit 8b909fa

Browse files
authored
docs: expand contract testing chapter (#66)
Closes #23 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 969a130 commit 8b909fa

4 files changed

Lines changed: 127 additions & 0 deletions

File tree

‎Cargo.toml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,7 @@ path = "examples/soluciones/property_testing_nivel_2.rs"
9090
[[example]]
9191
name = "property_testing_nivel_3"
9292
path = "examples/soluciones/property_testing_nivel_3.rs"
93+
94+
[[example]]
95+
name = "contract_testing"
96+
path = "examples/contract_testing.rs"

‎diagrams/06-contract-testing.mmd‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
flowchart LR
2+
C[Consumidor] --> R[Expectativa de operación]
3+
R --> K[Contrato explícito]
4+
K --> P[Proveedor]
5+
P --> V{¿Cambio compatible?}
6+
V -->|Sí| E[Verificación conserva expectativas]
7+
V -->|No| M[Versionar o coordinar migración]
8+
E --> D[Despliegue con menor incertidumbre]
9+
M --> D

‎docs/06-contract-testing.md‎

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,90 @@ contrato y razonar sobre compatibilidad sin agregar dependencias externas.
4848
El modelo representará la dirección del contrato, su compatibilidad y los
4949
riesgos que reducen la confianza de la verificación.
5050

51+
## Teoría
52+
53+
El contract testing parte de una frontera que ya existe: un consumidor necesita
54+
una operación y un proveedor la promete. La pregunta no es si ambos servicios
55+
funcionan aislados, sino si su lenguaje compartido sigue teniendo el mismo
56+
significado al evolucionar.
57+
58+
La compatibilidad hacia atrás permite que consumidores existentes sigan usando
59+
el contrato. Cuando una modificación no lo permite, la solución no es ocultarla
60+
en un mock: se necesita una versión, una migración o coordinación explícita.
61+
62+
## Diagrama
63+
64+
```mermaid
65+
flowchart LR
66+
C[Consumidor] --> R[Expectativa de operación]
67+
R --> K[Contrato explícito]
68+
K --> P[Proveedor]
69+
P --> V{¿Cambio compatible?}
70+
V -->|Sí| E[Verificación conserva expectativas]
71+
V -->|No| M[Versionar o coordinar migración]
72+
E --> D[Despliegue con menor incertidumbre]
73+
M --> D
74+
```
75+
76+
El archivo fuente vive en `diagrams/06-contract-testing.mmd`.
77+
78+
## Complejidad
79+
80+
El costo de un contrato crece con el número de consumidores y con la ambigüedad
81+
de sus expectativas. Una operación pequeña con errores explícitos suele ser más
82+
mantenible que una respuesta muy flexible cuyo significado depende de cada
83+
cliente.
84+
85+
## Implementación
86+
87+
`ContractDecision` en `src/contract_testing.rs` guarda la operación, la
88+
dirección del contrato, su compatibilidad y huecos como un cambio incompatible
89+
sin versionado o la ausencia de casos de error.
90+
91+
```rust
92+
use rust_testing::contract_testing::{
93+
Compatibility, ContractDecision, ContractDirection,
94+
};
95+
96+
let contract = ContractDecision::new(
97+
"consulta saldo",
98+
ContractDirection::ConsumerToProvider,
99+
Compatibility::BackwardCompatible,
100+
)?;
101+
102+
assert_eq!(contract.compatibility(), Compatibility::BackwardCompatible);
103+
# Ok::<(), rust_testing::contract_testing::ContractError>(())
104+
```
105+
106+
## Pruebas
107+
108+
El módulo incluye pruebas unitarias, un consumidor externo en
109+
`tests/contract_testing.rs` y un doctest. El test externo garantiza que el
110+
modelo se pueda observar solo desde su API pública.
111+
112+
## Benchmarks
113+
114+
No hay benchmark propio. El modelo clasifica decisiones y no representa el
115+
costo de verificar contratos distribuidos reales. `cargo bench --all-targets`
116+
se conserva como verificación de ruta.
117+
118+
## Ejemplos
119+
120+
```bash
121+
cargo run --example contract_testing
122+
```
123+
124+
El ejemplo muestra un contrato compatible y otro que es débil porque cambia sin
125+
versionarse.
126+
127+
## Ejercicios
128+
129+
Los ejercicios graduados y sus soluciones se agregan al cerrar el capítulo.
130+
131+
## Referencias internas
132+
133+
- RFC-0001 §13: Rust como núcleo técnico.
134+
- RFC-0001 §14: anatomía de cursos y capítulos.
135+
- RFC-0001 §20: revisión humana diferida.
136+
51137
No está marcado como `reviewed` ni `published`.

‎examples/contract_testing.rs‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use rust_testing::contract_testing::{
2+
Compatibility, ContractDecision, ContractDirection, ContractGap,
3+
};
4+
5+
fn main() -> Result<(), rust_testing::contract_testing::ContractError> {
6+
let compatible = ContractDecision::new(
7+
"consulta saldo",
8+
ContractDirection::ConsumerToProvider,
9+
Compatibility::BackwardCompatible,
10+
)?;
11+
let breaking = ContractDecision::new(
12+
"crea pedido",
13+
ContractDirection::ProviderToConsumer,
14+
Compatibility::CoordinatedChange,
15+
)?
16+
.with_gap(ContractGap::UnversionedBreakingChange);
17+
18+
for contract in [compatible, breaking] {
19+
println!(
20+
"{} => compatibilidad: {:?}, señal: {:?}, huecos: {:?}",
21+
contract.operation(),
22+
contract.compatibility(),
23+
contract.signal(),
24+
contract.gaps()
25+
);
26+
}
27+
Ok(())
28+
}

0 commit comments

Comments
 (0)