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étodo findById con el argumento 1.
  • Verificamos que el método getUserById de UserService 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étodo charge con el argumento 100.0.
  • Verificamos que el método processPayment de PaymentService devuelve true.

Ejercicio Práctico

Ejercicio 1: Mocking

  1. Crea una clase OrderService con un método placeOrder que dependa de una clase InventoryService para verificar el stock.
  2. Usa Spock para crear un mock de InventoryService y verifica que placeOrder llama al método checkStock.
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

  1. Crea una clase ShippingService con un método calculateShippingCost que dependa de una clase DistanceCalculator para calcular la distancia.
  2. 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.

© Copyright 2024. Todos los derechos reservados