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
Usercuando se llame al métodofindByIdcon el argumento1. - Verificamos que el método
getUserByIddeUserServicedevuelve 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
truecuando se llame al métodochargecon el argumento100.0. - Verificamos que el método
processPaymentdePaymentServicedevuelvetrue.
Ejercicio Práctico
Ejercicio 1: Mocking
- Crea una clase
OrderServicecon un métodoplaceOrderque dependa de una claseInventoryServicepara verificar el stock. - Usa Spock para crear un mock de
InventoryServicey verifica queplaceOrderllama 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
ShippingServicecon un métodocalculateShippingCostque dependa de una claseDistanceCalculatorpara calcular la distancia. - Usa Spock para crear un stub de
DistanceCalculatory 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
