lunes, 9 de junio de 2008

"Moqueando" clases abstractas con Rhino Mocks

Una interesante funcionalidad de RhinoMocks es la posiblidad de crear instancias de clases abstractas y utilizar sus método concretos sin más que la ayuda de los PartialMocks, incluso podemos dar comportamiento a sus métodos abstractos, con los cual es posible probar una clase abstracta en su totalidad sin tener una implementación concreta, vamos a ver en el famoso código autodescriptivo.

[TestClass]
public class UnitTest1
{
    MockRepository _repository;
    public MockRepository Mocker
    {
        get
        {
            if (_repository == null)
                _repository = new MockRepository();
            return _repository;
        }
    }
    /// <summary>
    /// Los PartialMocks nos permiten crear instancias de clases abstractas
    /// para poder probar los métodos concretos con su implementación real
    /// sin necesidad de heredar en una clase concreta
    /// </summary>
    [TestMethod]
    public void PartialMockTest()
    {
        //se pueden crear instancias de clases abstractas para utlizar los
        //métodos concretos
        AbstractProcessor processor = Mocker.PartialMock<AbstractProcessor>();

        //y funciona :-)
        Assert.AreEqual<string>("Hola Leonardo", processor.Saludar("Leonardo"));
    }

    /// <summary>
    /// No podemos modificar el comportamiento de método concreto
    /// </summary>
    [TestMethod]
    [ExpectedException(typeof(InvalidOperationException))]
    public void PartialMockConfigurarComportamientoMetodoConcreto()
    {
        AbstractProcessor processor = Mocker.PartialMock<AbstractProcessor>();

        using (Mocker.Record())
            Expect.Call(processor.Saludar("")).Return("Método modificado").IgnoreArguments();

        //utilizo la sintáxis de Record-Playback en lugar de ReplayAll-VerifyAll
        using (Mocker.Playback())
            Assert.AreEqual<string>("Método modificado", processor.MetodoUno());
    }

    /// <summary>
    /// También podemos configurar el comportamiento
    /// de los métodos abstratos y concretos
    /// </summary>
    [TestMethod]
    public void PartialMockConfigurarComportamientoMetodoAbstracto()
    {
        //se pueden crear instancias de clases abstractas para utlizar los
        //métodos concretos
        AbstractProcessor processor = Mocker.PartialMock<AbstractProcessor>();

        using (Mocker.Record())
            Expect.Call(processor.MetodoUno()).Return("Metodo1 moqueado");

        //utilizo la sintáxis de Record-Playback en lugar de ReplayAll-VerifyAll
        using (Mocker.Playback())
            Assert.AreEqual<string>("Metodo1 moqueado", processor.MetodoUno());
    }
}

/// <summary>
/// Una clase abstracta no se puede instanciar directamente
/// </summary>
public abstract class AbstractProcessor
{
    //método abstracto, sin implementaci´n
    public abstract string MetodoUno();
    //método concreto, para usarlo es necesario heredar esta clase
    public string Saludar(string nombre)
    {
        return string.Format("Hola {0}", nombre);
    }
}

Interesante, utilizalo con sabiduría, saludos