馃 Testing Duck Types
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.