lunes, 6 de octubre de 2008

¿Cómo verificar la cantidad de llamadas a un miembro con Moq?

¿Cómo verificar la cantidad de llamadas a un miembro con Moq?

Si hay utlizado Moq como yo también Rhino Mocks seguramente se han encontrado con la ausencia de un modo de verificar la cantidad de llamadas que se hacen sobre un miembre, digamos propiedad o método, o sea, configuramos nuestras Expectations y de alguna manera queresmos asegurarnos que tal miembro es llamado un número exácto de veces, es se hace en Rhino más o menos así

[TestMethod]
public void VerificarCantidadDeLlamadasConRhino()
{
    Rhino.Mocks.MockRepository mocker = new Rhino.Mocks.MockRepository();

    var mock = mocker.CreateMock<IFoo>();

    using (mocker.Record())
    {
        Rhino.Mocks.Expect.Call(mock.DoInt(2)).Return(22).Repeat.Times(3);
    }

    //Rhino hace la verificación al salir del bloque using
    using (mocker.Playback())
    {
        Assert.AreEqual<int>(22, mock.DoInt(2));
        Assert.AreEqual<int>(22, mock.DoInt(2));
        Assert.AreEqual<int>(22, mock.DoInt(2));
    }
}

 

Ahora bien, nuestro querido Moq no dispones de esa característica,¿ por qué?, porque la idea de Kzu es que Moq sea muy sencillo (no entremos en discusiones del tipo por qué se mezclan Stubs y Mocks porque no tienen sentido) esto es muy bueno y la verdad es que me encanta, pero nos deja con ese problema, cómo lo resolvemos?

Callbacks, la solución

Los Callbacks son acciones que podemos indicar al Moq que realize un Mock cuando se invoca a uno de sus miembros, o sea, configuramos un Expectation a un miembro y de paso le podemos decir a Moq que cuando este miembro sea invocado que haga algo más que puede no tener ninguna relación con el Mock, entonces lo que tenemos que hacer para verificar que un método es llamado un número exácto de veces (o mayor o menor, lo que sea) es configurar un Callback en el miembro que incremente un contador y luego con un Assert verificar el contador, y listo el pollo, de esta manera:

[TestMethod]
public void VerificarCantidadDeLlamadasConMoq()
{
    var mock = new Mock<IFoo>();
    int contador = 0;

    //al configurar el Expectation agregamos un Callback que incrementa contador
    mock.Expect(x => x.DoInt(2)).Returns(22).Callback(()=>contador++);

    Assert.AreEqual<int>(22, mock.Object.DoInt(2));
    Assert.AreEqual<int>(22, mock.Object.DoInt(2));
    Assert.AreEqual<int>(22, mock.Object.DoInt(2));

    //verificamos contador y listo
    Assert.AreEqual<int>(3,contador);
}

Conclusión

Personalmente me sigue pareciendo mucho más clara la sintáxis de Moq, en definitiva puede ser que Moq sea demasiado sencillo y mezcle conceptos de TDD para serlo, pero la realidad es que es mejor ser productivo que ortodoxo, no? hasta la próxima.