Optimise Rhino.Mocks tests using a base class

27 Apr

It’s usual my team to use ModelViewPresenter pattern and than use Rhino.Mocks to test Presenter without concrete View and Model. Rhino.Mock is a great tool but its usage can be quite booring as it requires some repeated code for each test. Here a sample:

    public class Presenter
    {
        public Presenter(IView view, IModel model)
        {
            model.Loaded += delegate { throw new NotImplementedException(); };
        }
    }

    public interface IModel
    {
        event EventHandler Loaded;
    }

    public interface IView
    {
    }

I want to test that during constructor Presenter subscribe model Loaded event. So I need to write this unit test using Rhino.Mocks:

[TestFixture]
public class ClassicMockingSample
{
    private IView _view;
    private IModel _model;
    private MockRepository _repository;

    [SetUp]
    public void SetUp()
    {
        _repository = new MockRepository();
        _view = _repository.Stub<IView>();
        _model = _repository.CreateMock<IModel>();
    }

    [Test]
    public void Ctor_Always_SubscribeModelEvents()
    {

        using (_repository.Record())
        {
            Expect.Call(delegate { _model.Loaded += null; })
                .Constraints(Is.NotNull());
        }
        using (_repository.Playback())
        {
            new Presenter(_view, _model);
        }
    }
}

Looking at NBehave framework I discover a usefull class SpecBase that hides the codes needed to create MockRepository repository and give you more readable code.
Here the same test as shown before but refactored using SpecBase class

[Context]
public class NBehaveLikeMockingSample : SpecBase
{
    private IModel model;
    private IView view;

    protected override void Before_each_spec()
    {
        model = Mock<IModel>();
        view = Stub<IView>();
    }

    [Specification]
    public void Ctor_Always_SubscribeModelEvents()
    {
        using (RecordExpectedBehavior)
        {
            Expect.Call(delegate { model.Loaded += null; })
                .Constraints(Is.NotNull());
        }
        using (PlaybackBehavior)
        {
            new Presenter(view, model);
        }
    }
}

As you can see there is nothing magic here.
It’ just a more readable unit test. Context and Specification attribute are alias of MbUnit attribute

using Context = MbUnit.Framework.TestFixtureAttribute;
using Specification = MbUnit.Framework.TestAttribute;

As I don’t need all the NBehave framework for the moment I decided to copy the class SpecBase inside my UnitTest Assembly after removing the AutoMocking feature.The code it’s here:

public class SpecBase
{
    private MockRepository _mocks;

    protected IDisposable RecordExpectedBehavior
    {
        get { return _mocks.Record(); }
    }

    protected IDisposable PlaybackBehavior
    {
        get { return _mocks.Playback(); }
    }

    [SetUp]
    public void MainSetup()
    {
        _mocks = new MockRepository();
        Before_each_spec();
    }

    [TearDown]
    public void MainTeardown()
    {
        After_each_spec();
    }

    protected virtual void Before_each_spec()
    {

    }

    protected virtual void After_each_spec()
    {
    }

    protected TType Mock<TType>()
    {
        return _mocks.DynamicMock<TType>();
    }

    protected TType Mock<TType>(object[] prams)
    {
        return _mocks.DynamicMock<TType>(prams);
    }

    protected TType Partial<TType>()
        where TType : class
    {
        return _mocks.PartialMock<TType>();
    }

    protected TType Stub<TType>()
    {
        return _mocks.Stub<TType>();
    }

    protected void Verify(object mock)
    {
        _mocks.Verify(mock);
    }

    protected void VerifyAll()
    {
        _mocks.VerifyAll();
    }

    protected void Spec_not_implemented()
    {
        Assert.Ignore("Spec not implemented");
    }
}
Technorati Tag: ,,

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...

%d blogger cliccano Mi Piace per questo: