Raising events (from a mock) using Rhino Mocks in VB.Net

Standard

 I’ve been doing some investigation of Passive View (MVP) architecture for Smart Client applications.

 The article Raising events (from a mock) using Rhino Mocks By Jean-Paul S. Boodhoo outlines the issues and gives some solutions to mocking “View” classes in MVP from a C# point of view.  In this post I’ll show some equivalent VB.Net code samples.

About Passive View 

The Passive View involves three components:

  • Model – Responsible for reading, saving  and validating the business data
  • View – Responsible for displaying data and accepting input from the user
  • Presenter – It provides the “glue” between the View and Presenter.  It copies data from the Model to the View and relays commands from the View to the Model.

(This differs from MVC in that there is no direct communication between Model and View)

The model and the view implement interfaces which are used by the Presenter to communicate with them.

By utilising interfaces, these interfaces can be “Mocked” using a mocking framework such as Rhino Mock.

About Mocking

The purpose of mocking is to ease testing by allowing the developer to create mock implementations of custom objects and verify the interactions using unit testing.

In MVP, the view is usually implemented by a difficult-to-test (or slow-to-test) user interface form.  Using a Mocking framework allows you to create a substitute for the user interface that runs quickly and accurately simulates the user interface from the Presenter’s viewpoint.

Find out more about Rhino Mocks at it’s project page.

Raising Events

An important aspect of the View interface is that it defines events that are raised in order to communicate input actions to the Presenter.

This is not completely straight forward.

Here’s an example of one of a View interface:

Public Interface IPersonalView
    Property Name() As String
    Property Address() As String
    Property Age() As Integer
    Event OnRead()
    Event OnSave()
End Interface

Here’s an example of a presenter that consumes views that implement the IPersonalView interface:

Public Class PersonalPresenter

    Protected WithEvents View As IPersonalView
    Protected Model As IPersonalModel
    Public Sub New(ByVal view As IPersonalView, ByVal model As IPersonalModel)
        Me.View = view
        Me.Model = model
    End Sub

    Public Sub DisplayCustomerDetails() Handles View.OnRead

        ' Ask Model to populate itself
        Model.DoRead()

        ' Transfer information
        With Me.View
            .Name = Model.Name
            .Address = Model.Address
            .Age = Model.Age
        End With

    End Sub
    Public Sub DoUpdate() Handles View.OnSave
        With Me.Model
            .Name = View.Name
            .Address = View.Address
            .Age = View.Age
        End With

        Model.DoSave()
    End Sub

End Class

You’ll notice that the first thing the presenter does (using the WithEvents keyword) is subscribe to events. 

In order to correctly “mock” a view then, we have to program the mock to expect this subscription.  Here is a Test:

<TestClass()> _
Public Class PersonalPresenterTest

    Private moMockery As MockRepository
    <TestInitialize()> _
    Public Sub MyTestInitialize()
        moMockery = New MockRepository

    End Sub

    <TestCleanup()> _
    Public Sub MyTestCleanup()

        moMockery.VerifyAll()

    End Sub
    <TestMethod()> _
    Public Sub Construction_ShouldSubscribeToEventsOnView()
        ' Mock the View
        Dim loView As IPersonalView = moMockery.CreateMock(Of IPersonalView)() 

        AddHandler loView.OnRead, Nothing
        LastCall.Constraints(Constraints.Is.NotNull())

        AddHandler loView.OnSave, Nothing
        LastCall.Constraints(Constraints.Is.NotNull())

        moMockery.ReplayAll()
        Dim target As PersonalPresenter = New PersonalPresenter(loView, Nothing)

    End Sub

End Class

 The important lines here are:

AddHandler loView.OnRead, Nothing
LastCall.Constraints(Constraints.Is.NotNull())
 The first line simulates what the WithEvents call does, which is to call AddHandler on all the handled events.

Raising An Event

Listening for the wireup isn’t enough however.    To properly simulate true view actions, we need to raise events to the Presenter (such as OnRead).  Rhino Mock provides a special object called an “EventRaiser”.

Call LastCall.GetEventRaiser after the AddHandler to get this object, then call the Raise method to raise the event:

' Mock the View
Dim loView As IPersonalView = moMockery.CreateMock(Of IPersonalView)() 

AddHandler loView.OnRead, Nothing
LastCall.Constraints(Constraints.Is.NotNull())

Dim loOnReadEventRaiser As Rhino.Mocks.Interfaces.IEventRaiser = LastCall.GetEventRaiser

AddHandler loView.OnSave, Nothing
LastCall.Constraints(Constraints.Is.NotNull())

moMockery.ReplayAll()

Dim target As PersonalPresenter = New PersonalPresenter(loView, loModel)

' Raise the read event on the "view"
loOnReadEventRaiser.Raise()

This gives me the fundamental building blocks for mocking views.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s