Resumen¶
- Las clases testables inyectan las dependencias y los stubs (dobles de pruebas) controlan los valores que devuelven las funciones invocadas desde la dependencia.
Flujo de dependencias y ficheros¶
El código presentado sigue un enfoque de pruebas unitarias en Java, separando la lógica de negocio de las dependencias externas para facilitar la inyección de stubs durante los tests.

La dependencia fija es la instancia de IService y buscarDatos.elemPendientes(cli) es un método de la dependencia del cual necesitamos controlar su valor.
- Se instancia la STUB,
BuscadorSTUB, que dará el valor a la llamada abuscarDatos.elemPendientes()cuando se llame desde el test (sut.generarFactura(cli)).
BuscadorSTUB stub = new BuscadorSTUB(10); // Devolverá 10 cuando elemPendientes() sea llamado
- Se instancia la Testable,
GestorPedidosTestable.
GestorPedidosTestable sut = new GestorPedidosTestable();
- Se inyecta el Stub en la SUT, mediante el setter
setBuscador(stub)se sobre escribe la instancia deIServiceen la sut (IService buscarDatos = getBuscador();).
sut.setBuscador(stub); // Reemplaza la dependencia fija con el Stub
- Se ejecuta el test, llamando al método de la sut.
Factura expectedResult = new Factura(...);
Factura realResult = assertDoesNotThrow(() -> sut.generarFactura(cli));
assertEquals(expectedResult, realResult);
1. Código de producción (SUT) - GestorPedidos.java¶
Ubicación: /src/main/java
Archivo: GestorPedidos.java
Propósito:
Este es el código original de la SUT (System Under Test). Tiene un método generarFactura() que usa una dependencia IService para obtener información sobre los elementos pendientes.
public class GestorPedidos {
public IService getBuscador() {
IService buscar = new Buscador();
return buscar;
}
public Factura generarFactura(Cliente cli) throws FacturaException {
Factura factura = new Factura();
IService buscarDatos = getBuscador();
int numElems = buscarDatos.elemPendientes(cli);
if (numElems > 0) {
// código para generar la factura
factura = ...;
} else {
throw new FacturaException("No hay ...");
}
return factura;
}
}
Problema:
getBuscador()crea directamente una instancia deBuscador(), lo que hace difícil reemplazar esta dependencia con un stub en las pruebas.- No es posible controlar el comportamiento de
elemPendientes()en un entorno de pruebas.
Solución:
Refactorizamos GestorPedidos para permitir la inyección de dependencias, creando una subclase GestorPedidosTestable.
2. Implementación del Stub - BuscadorSTUB.java¶
Ubicación: /src/test/java
Archivo: BuscadorSTUB.java
Propósito:
Este es un stub (doble de prueba) que implementa IService. Nos permite controlar el valor devuelto por elemPendientes() en los tests.
public class BuscadorSTUB implements IService {
int resultado;
public BuscadorSTUB(int salida) {
this.resultado = salida;
}
@Override
public int elemPendientes(Cliente cli) {
return resultado;
}
}
Beneficio:
- Nos permite controlar el número de elementos pendientes sin depender de la implementación real de
Buscador. - Evita acceder a una base de datos o sistema externo en los tests.
3. Subclase de GestorPedidos para permitir inyección - GestorPedidosTestable.java¶
Ubicación: /src/test/java
Archivo: GestorPedidosTestable.java
Propósito:
Esta clase hereda de GestorPedidos y sobrescribe getBuscador() para permitir la inyección de un stub en lugar del buscador real.
public class GestorPedidosTestable extends GestorPedidos {
IService busca;
@Override
public IService getBuscador() {
return busca;
}
public void setBuscador(IService b) {
this.busca = b;
}
}
Beneficio:
- Permite asignar un stub en tiempo de prueba con
setBuscador(stub). - Separa la lógica de producción de la de prueba sin modificar
GestorPedidos.
4. Prueba unitaria - GestorPedidosTest.java¶
Ubicación: /src/test/java
Archivo: GestorPedidosTest.java
Propósito:
Esta clase es el driver, el código que ejecuta la prueba unitaria.
public class GestorPedidosTest {
@Test
public void testGenerarFactura() {
Cliente cli = new Cliente(...);
BuscadorSTUB stub = new BuscadorSTUB(10);
GestorPedidosTestable sut = new GestorPedidosTestable();
sut.setBuscador(stub);
Factura expectedResult = new Factura(...);
Factura realResult = assertDoesNotThrow(() -> sut.generarFactura(cli));
assertEquals(expectedResult, realResult);
}
}
Beneficio:
- Se crea un stub (
BuscadorSTUB(10)) que devuelve siempre10elementos pendientes. - Se inyecta este stub en
GestorPedidosTestableusandosetBuscador(stub). - La prueba valida que
generarFactura()funciona correctamente sin depender deBuscador.
Resumen del flujo de dependencias¶
Código de producción (src/main/java)
GestorPedidos.java: Implementa la funcionalidad principal (SUT).- Contiene una dependencia
IService, que en producción esBuscador().
Código de pruebas (src/test/java)
BuscadorSTUB.java: Implementa un stub deIServicepara pruebas.GestorPedidosTestable.java: Clase que permite inyectar el stub en lugar deBuscador().GestorPedidosTest.java: Prueba unitaria que usaGestorPedidosTestablecon un stub.
Conclusión¶
- Se logra desacoplar la SUT de la implementación real de
Buscador. - Se facilita la prueba de
GestorPedidoscon datos controlados. - Se aplican principios de inyección de dependencias y diseño orientado a pruebas.
Generalización¶
-
Los STUBS
- Son dobles de prueba que reemplazan una dependencia real en la SUT.
- Se usan para controlar los valores de retorno de métodos en dependencias externas o fijas.
- Evitan interacciones con sistemas reales como bases de datos, APIs externas, etc.
- Permiten pruebas deterministas con valores predefinidos.
-
Las clases Testable
- Se crean cuando la SUT tiene dependencias fijas y no inyectables.
- Su propósito es permitir la inyección de dependencias mediante métodos como
setDependencia(). - Suelen sobrescribir métodos que crean instancias de dependencias fijas, sustituyéndolas por versiones inyectables.
- No modifican la SUT original, sino que la extienden para hacerla testeable sin cambiar su comportamiento en producción.
En conjunto, los stubs permiten controlar el comportamiento de dependencias y las clases testables hacen posible la inyección de esas dependencias en la SUT para realizar pruebas unitarias de manera controlada.