En este módulo, aprenderemos sobre dos técnicas fundamentales en las pruebas unitarias: Mocking y Stubbing. Estas técnicas son esenciales para aislar el código que estamos probando y simular el comportamiento de dependencias externas.
¿Qué es Mocking?
Mocking es una técnica utilizada en las pruebas unitarias para crear objetos simulados que imitan el comportamiento de objetos reales. Estos objetos simulados, conocidos como "mocks", permiten verificar que ciertas interacciones ocurren como se espera.
Ventajas del Mocking
- Aislamiento: Permite probar una unidad de código en aislamiento, sin depender de otras partes del sistema.
- Control: Proporciona control sobre el comportamiento de las dependencias externas.
- Verificación: Permite verificar que ciertas interacciones ocurrieron durante la prueba.
Ejemplo de Mocking en Groovy con Spock
import spock.lang.Specification class UserService { UserRepository userRepository User getUserById(Long id) { return userRepository.findById(id) } } class UserRepository { User findById(Long id) { // Lógica para encontrar un usuario por ID } } class UserServiceSpec extends Specification { def "should return user by id"() { given: def userRepository = Mock(UserRepository) def userService = new UserService(userRepository: userRepository) def user = new User(id: 1, name: "John Doe") when: userRepository.findById(1) >> user then: userService.getUserById(1) == user } }
En este ejemplo:
- Creamos un mock de
UserRepository
. - Configuramos el mock para que devuelva un objeto
User
cuando se llame al métodofindById
con el argumento1
. - Verificamos que el método
getUserById
deUserService
devuelve el usuario esperado.
¿Qué es Stubbing?
Stubbing es una técnica utilizada para proporcionar respuestas predefinidas a llamadas de métodos durante una prueba. A diferencia del mocking, el stubbing no verifica las interacciones, solo proporciona datos simulados.
Ventajas del Stubbing
- Simplicidad: Facilita la configuración de dependencias externas con respuestas predefinidas.
- Rapidez: Permite simular respuestas rápidas sin ejecutar lógica compleja.
Ejemplo de Stubbing en Groovy con Spock
import spock.lang.Specification class PaymentService { PaymentGateway paymentGateway boolean processPayment(double amount) { return paymentGateway.charge(amount) } } class PaymentGateway { boolean charge(double amount) { // Lógica para procesar el pago } } class PaymentServiceSpec extends Specification { def "should process payment successfully"() { given: def paymentGateway = Stub(PaymentGateway) def paymentService = new PaymentService(paymentGateway: paymentGateway) when: paymentGateway.charge(100.0) >> true then: paymentService.processPayment(100.0) == true } }
En este ejemplo:
- Creamos un stub de
PaymentGateway
. - Configuramos el stub para que devuelva
true
cuando se llame al métodocharge
con el argumento100.0
. - Verificamos que el método
processPayment
dePaymentService
devuelvetrue
.
Ejercicio Práctico
Ejercicio 1: Mocking
- Crea una clase
OrderService
con un métodoplaceOrder
que dependa de una claseInventoryService
para verificar el stock. - Usa Spock para crear un mock de
InventoryService
y verifica queplaceOrder
llama al métodocheckStock
.
class OrderService { InventoryService inventoryService boolean placeOrder(String item, int quantity) { return inventoryService.checkStock(item, quantity) } } class InventoryService { boolean checkStock(String item, int quantity) { // Lógica para verificar el stock } } class OrderServiceSpec extends Specification { def "should check stock when placing an order"() { given: def inventoryService = Mock(InventoryService) def orderService = new OrderService(inventoryService: inventoryService) when: orderService.placeOrder("item1", 10) then: 1 * inventoryService.checkStock("item1", 10) } }
Ejercicio 2: Stubbing
- Crea una clase
ShippingService
con un métodocalculateShippingCost
que dependa de una claseDistanceCalculator
para calcular la distancia. - Usa Spock para crear un stub de
DistanceCalculator
y proporciona una distancia predefinida para calcular el costo de envío.
class ShippingService { DistanceCalculator distanceCalculator double calculateShippingCost(String from, String to) { double distance = distanceCalculator.calculateDistance(from, to) return distance * 0.5 // Costo por unidad de distancia } } class DistanceCalculator { double calculateDistance(String from, String to) { // Lógica para calcular la distancia } } class ShippingServiceSpec extends Specification { def "should calculate shipping cost based on distance"() { given: def distanceCalculator = Stub(DistanceCalculator) def shippingService = new ShippingService(distanceCalculator: distanceCalculator) when: distanceCalculator.calculateDistance("A", "B") >> 100.0 then: shippingService.calculateShippingCost("A", "B") == 50.0 } }
Conclusión
En esta sección, hemos aprendido sobre las técnicas de Mocking y Stubbing en Groovy utilizando el framework de pruebas Spock. Estas técnicas son esenciales para escribir pruebas unitarias efectivas y garantizar que nuestro código funcione correctamente en aislamiento. Asegúrate de practicar estos conceptos con los ejercicios proporcionados para reforzar tu comprensión. En el próximo módulo, exploraremos la depuración de código Groovy.
Curso de Programación Groovy
Módulo 1: Introducción a Groovy
Módulo 2: Sintaxis de Groovy y Características del Lenguaje
Módulo 3: Programación Orientada a Objetos en Groovy
Módulo 4: Características Avanzadas de Groovy
Módulo 5: Groovy en la Práctica
- Entrada/Salida de Archivos
- Trabajando con XML y JSON
- Acceso a Bases de Datos
- Desarrollo Web con Groovy
Módulo 6: Pruebas y Depuración
Módulo 7: Ecosistema y Herramientas de Groovy
- Herramienta de Construcción Gradle
- Framework de Pruebas Spock
- Framework Grails
- Otras Bibliotecas y Herramientas de Groovy
Módulo 8: Mejores Prácticas y Temas Avanzados
- Estilo de Código y Convenciones
- Optimización del Rendimiento
- Consideraciones de Seguridad
- Concurrencia en Groovy