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>
HelloWorld! <YOUR TEXT>
gets put on the label.
Sample code below, but in a nutshell:
//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.
IHelloWorldView
[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. eg
//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.
You are setting up the view-mock with DefaultValue.Mock, so your view will have an initialized Model property. Instead of utilizing Moq to check the value of the model, just check the Message directly on your model:
Assert.That(mock.Object.Model.Message, Is.EqualTo(expected));
The beauty of this small (but semantically equal) change is that your mock suddenly becomes a stub and your are testing end result instead of nitty gritty implementation details. As for your questions, its a good thing to design your system in terms of testability, but I would not start to virtualize or interface everything just to make it Moq-friendly; make a SOLID architecture, not necessary Moq-able.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.