Diseño ágil con TDD

6.2. La metáfora Record/Replay

Algunos frameworks de mocks como EasyMock (y en versiones anteriores, también Rhino.Mocks) usan la metáfora conocida como Record/Replay. Necesitan que les indiquemos explícitamente cuándo hemos terminado de definir expectativas para comenzar el acto. Afortunadamente, es fácil hacerlo, es una línea de código pero a la gente le choca esto de record y replay. Si hemos comprendido todos los tests de este capítulo, la metáfora no será ningún problema. EasyMock es para Java. Veamos la versión Java del ejemplo del calendario:

import staticorg.junit.Assert.*;
import org.junit.Test;
import java.util.Calendar;
import staticorg.easymock.EasyMock.*;

public class CalendarTests
{
    @Test
    public void drawHolidays()
    {
        int year = 2009;
        int month = 2;
        String townCode = "b002";
        ICalendarService serviceMock = createMock(ICalendarService.class);

        expect(serviceMock.getHolidays(
            year, month, townCode)
            ).andReturn(new int[] { 1, 5 });

        replay(serviceMock);

        Calendar calendar = new Calendar(serviceMock);
        calendar.set_currentTown(townCode);
        calendar.set_currentYear(year);
        calendar.set_currentMonth(month);
        calendar.drawMonth();

        verify(serviceMock);
    }
}

Prácticamente todo igual. Lo único es que hemos tenido que decir explícitamente replay(serviceMock) para cambiar de estado al mock. Si se nos olvida activar el replay, el resultado del test es bastante raro puesto que, lo que debería ser el acto se sigue considerando la preparación y es desconcertante. Suele pasar al principio con este tipo de frameworks.

La documentación de EasyMock es concisa, siendo recomendable dedicar unos minutos a revisarla para descubrir toda su funcionalidad. Al igual que la de Rhino.Mocks, contiene ejemplos que reforzarán los conceptos expresados en estas líneas. La metáfora que acabamos de ver no aporta ninguna ventaja al desarrollo y, de hecho, en Rhino.Mocks ya se hace implícita. El motivo por el que algunos frameworks la mantienen es para hacer más sencilla la implementación de los mocks internamente, es decir, que es una limitación en lugar de una ventaja.

Mi framework de mocks favorito en Java, a día de hoy, es Mockito ya que es más sencillo que EasyMock. Produce un código más claro y la metáfora de record/replay ya se ha superado. Para Mockito no hay que utilizar distintos métodos a la hora de crear un stub y un mock. En principio todos los dobles se crean con el método mock, aunque luego sea un stub. La diferencia queda implítica en la forma en que utilicemos el doble. Así por ejemplo, para definir un mock con una expectativa, podemos hacer lo siguiente:

@Test
public void persistorSaves() throws Exception {
    EmailAddress emailMock = mock(EmailAddress.class);
    Persistor<EmailAddress> persistor = newPersistor<EmailAddress>();

    persistor.Save(emailMock);
    verify(emailMock).save();
}

El test dice que nuestro SUT (Persistor) tiene que invocar forzosamente en algún momento al método save del colaborador, que es de tipo EmailAddress. Los dobles de prueba en Mockito son, por defecto, una especie de mock híbrido o relajado que no tiene en cuenta el orden de las expectativas u otras posibles llamadas, salvo que se especifique con código, lo cual se agradece la mayoría de las veces. Es similar al GenerateMock de Rhino.Mocks.

Por último, nos queda ver cómo se trabaja en Python pero lo haremos en la parte práctica del libro, porque tanto con Python Mocker como con PyMox, se trabaja prácticamente igual a como acabamos de estudiar. Mocker funciona francamente bien pero su desarrollo lleva tiempo parado, mientras que el de Pymox sigue activo y su sintáxis se parece aún más a EasyMock o Rhino.Mocks.

Algunas de las preguntas que quedan abiertas en el presente capítulo, se resolverán en los siguientes.


Copyright (c) 2010-2013 Carlos Ble. La copia y redistribución de esta página se permite bajo los términos de la licencia Creative Commons Atribución SinDerivadas 3.0 Unported siempre que se conserve esta nota de copyright.