I'm trying to test a Presenter created using ASP.NET WebFormsMVP. I'm building it using a "Supervising Controller" pattern so the View is responsible for updating itself from the Model. I've simplified down the following example of a page with a textbox, a button & label. You type in the textbox & press the button and the text HelloWorld! <YOUR TEXT>
gets put on the label.
Sample code below, but in a nutshell:
- the button_click will raise a View Event.
- the Presenter subscribes to this ViewEvent and catches the args (i.e. the message)
- the Presenter does the work (string concatenation) and updates the Model
- the view rebinds to the Model.Message property & it all works fine.
//Model
public class HelloWorldModel {
public string Message { get; set; }
}
//Args
public class HelloWorldEventArgs : EventArgs {
public string Message { get; set; }
}
//View
public interface IHelloWorldView : IView<HelloWorldModel> {
event EventHandler<HelloWorldEventArgs> SendMessage;
}
//Presenter
public class HelloWorldPresenter : Presenter<IHelloWorldView>
{
private readonly EventHandler<HelloWorldEventArgs> SendMessageDelegate;
public HelloWorldPresenter(IHelloWorldView view) : base(view)
{
SendMessageDelegate = ((s, e) => SendMessageReceived(e.Message));
View.SendMessage += SendMessageDelegate;
}
public override void ReleaseView()
{
View.SendMessage -= SendMessageDelegate;
}
public void SendMessageReceived(string message)
{
View.Model.Message = string.Format("Hello World! - {0}", message);
}
}
//View implementation
[PresenterBinding(typeof(HelloWorldPresenter))]
public partial class HelloWorld : MvpPage<HelloWorldModel>,IHelloWorldView
{
protected void EchoButtonClick(object sender, EventArgs e)
{
if(SendMessage != null)
{
var args = new HelloWorldEventArgs {Message = MessageTextBox.Text};
SendMessage(sender, args);
}
}
public event EventHandler<HelloWorldEventArgs> SendMessage;
}
My problem lies with the testing though.
Since the View is responsible for updating itself from the model, the Presenter only sets the Model.Message Property... so in a Unit Test, I want to do the following.
- Mock my
IHelloWorldView
- Instantiate my Present with the Mock.
- Trigger the event on the Mock
- Verify that the present set the Model.Message Property of the Mock.
[TestMethod]
public void TestMethod1()
{
var input = "My Message";
var expected = string.Format("Hello World! - {0}", input);
var mock = new Mock<IHelloWorldView>
{
DefaultValue = DefaultValue.Mock
};
var pres = new HelloWorldPresenter(mock.Object);
mock.Raise(m =>
m.SendMessage += null,
new HelloWorldEventArgs { Message = input });
mock.VerifySet(view =>
view.Model.Message = It.Is<string>(s => s == expected),
Times.Once());
}
But this won't work unless I explicity mark the Message
Property of my Model as virtual which I don't really want to do. e.g.
//Model
public class HelloWorldModel {
public string Message { get; set; }
}
My Other Option is to use a Passive View Pattern and expose the asp:label Text as a string property on the IHelloWorldView and set that directly from the Presenter... and then I should be able to test it.
- Is Passive View a better approach from a testing point of view ?
- Is it necessary that I should have to either Also Mock my Model (which I'm not sure is possible in WebFormsMVP? OR
- That I need to make all the properties of my Model Virtual OR
- Have I missed the point somewhere?