馃 Testing Duck Types

馃И Testing
馃搮 2023-11-04

Al trabajar con la programaci贸n orientada a objetos, especialmente en sistemas complejos, a menudo surge la necesidad de trabajar con tipos abstractos en lugar de clases concretas. Este enfoque, conocido como "duck typing", nos permite enfocarnos en el comportamiento que un objeto puede soportar, en lugar de la clase del objeto per se. En Python, "duck typing" es un concepto clave debido a su naturaleza din谩mica y su filosof铆a de "si camina como un pato y hace quack como un pato, entonces debe ser un pato".

Definiendo la Interfaz de Preparaci贸n de Eventos

Imaginemos que estamos dise帽ando un sistema que organiza eventos. Tenemos diferentes tipos de organizadores de eventos, cada uno con su propio conjunto de responsabilidades. Para mantener un dise帽o limpio, definimos una interfaz abstracta EventOrganizer y aseguramos que todos los organizadores la implementen.

from abc import ABC, abstractmethod

class EventOrganizer(ABC):
    @abstractmethod
    def organize(self, event):
        pass

Cada organizador de eventos (Caterer, Musician, Decorator) implementa el m茅todo organize para preparar su parte del evento.

class Caterer(EventOrganizer):
    def organize(self, event):
        # Implementaci贸n espec铆fica del Caterer
        pass

class Musician(EventOrganizer):
    def organize(self, event):
        # Implementaci贸n espec铆fica del Musician
        pass

class Decorator(EventOrganizer):
    def organize(self, event):
        # Implementaci贸n espec铆fica del Decorator
        pass

La clase Event es responsable de orquestar la preparaci贸n, invocando el m茅todo organize de cada organizador.

class Event:
    def __init__(self, organizers):
        self.organizers = organizers

    def prepare(self):
        for organizer in self.organizers:
            organizer.organize(self)

Escribiendo Pruebas Compartibles para Duck Types

El uso de "duck types" nos lleva a la pregunta de c贸mo probar efectivamente este comportamiento. La clave es escribir pruebas que puedan ser compartidas por todos los jugadores del rol EventOrganizer. Usaremos el framework unittest de Python para hacer esto.

Creamos un test case base que cualquier organizador de eventos puede utilizar para probar si cumple con la interfaz EventOrganizer.

import unittest

class EventOrganizerTestCase(unittest.TestCase):
    def setUp(self):
        self.object = self.get_organizer()

    @abstractmethod
    def get_organizer(self):
        pass

    def test_implements_event_organizer_interface(self):
        self.assertTrue(hasattr(self.object, 'organize'))

A continuaci贸n, extendemos este test case para cada tipo de organizador de eventos.

class CatererTest(EventOrganizerTestCase):
    def get_organizer(self):
        return Caterer()

class MusicianTest(EventOrganizerTestCase):
    def get_organizer(self):
        return Musician()

class DecoratorTest(EventOrganizerTestCase):
    def get_organizer(self):
        return Decorator()

Con estos test cases, podemos asegurarnos de que cada organizador implemente el m茅todo organize requerido por la interfaz EventOrganizer.

Pruebas de Colaboraci贸n

Adem谩s de probar que los organizadores cumplen con la interfaz, necesitamos asegurarnos de que la clase Event interact煤a correctamente con los EventOrganizer. Esto se logra simulando (mocking) los objetos y asegur谩ndonos de que se llama al m茅todo organize.

class EventTest(unittest.TestCase):
    def test_prepares_with_organizers(self):
        organizer_mock = unittest.mock.Mock(spec=EventOrganizer)
        event = Event([organizer_mock])

        event.prepare()

        organizer_mock.organize.assert_called_once_with(event)

Ejecutar estas pruebas asegura que nuestro sistema est谩 bien integrado y que las interacciones entre los diferentes componentes son como se esperan.

Conclusi贸n

En conclusi贸n, "duck typing" y las pruebas compartibles proporcionan un marco poderoso para construir y asegurar sistemas flexibles y mantenibles. Aunque Python no tiene interfaces en el mismo sentido que otros lenguajes de programaci贸n, la filosof铆a de "duck typing" y las pruebas s贸lidas nos permiten dise帽ar e implementar sistemas robustos y flexibles.

馃摎 Referencias