Testing WinForms MVP and Event mechanism with moq
I've been using MVP pattern in my application. But I have problems with testing my method which are called after button is clicked. Here is the code:
public interface IControl
{
bool Enabled { get; set; }
string Text { get; set; }
}
public interface IButton : IControl
{
event EventHandler Click;
}
public class Button : System.Windows.Forms.Button, IButton
{ }
public interface IForm : IControl
{
void Show();
void Close();
}
public interface IView : IForm
{
IButton Button1 { get; }
}
public partial class View : Form, IView
{
public View()
{
InitializeComponent();
}
#region IView Members
public IButton Button1
{
get { return button1; }
}
#endregion
}
public class Presenter
{
IView v开发者_高级运维iew;
public Presenter(IView view)
{
this.view = view;
this.view.Button1.Click += ButtonClick;
this.view.Show();
}
private void ButtonClick(object sender, EventArgs e)
{
view.Button1.Text= "some text";
}
}
The problem is that I don't know how to write test so that my ButtonClick method get called. I tried like this:
var view = new Mock<IView>();
view.Setup(x => x.Button1).Returns(new Mock<IButton>().SetupAllProperties().Object);
Presenter presenter = new Presenter(view.Object);
view.Raise(x => x.Button1.Click+= null, EventArgs.Empty);
Assert.AreEqual("some text", view.Object.Button1.Text);
I think that problem is in this line:
this.view.Button1.Click += ButtonClick;
It seems that Click event doesn't remember ButtonClick method. How to make Click to be stub to work just normal. Any suggestion is welcome. Thanks in advance. Regards, Vajda
EDIT: I was able to do that when I created SubscribeOnClick(EventHandler click); method in my IButton interface instead of event EventHandler Click. And I made some ButtonMock where I remembered method. But still, if someone knows for better solution, please share with me.
Maybe it's not a bad idea to use the command pattern here. Your IView
is very implementation specific because it has a prescribed number of controls that should have a Click
event (I know it is an example, but still...).
A simple implementation of the command pattern would be to let IView
have a List<Action>
that is supplied by the presenter, and let a specific implementation of a view decide how to fire these actions, e.g. by doing
this.button1.Click += (sender, e) => this.Actions[0]();
A mock object would not need to have a Click event (which may not even be supported by Moq, I'm not sure). You could just have it fire one of its actions.
I Changed my IButton interface to this one:
public interface IButton : IControl
{
voie SUbscribeOnClick(EventHandler click);
}
public class ButtonStub : IButton
{
EventHandler click;
public bool Enabled { get; set; }
public void SubscribeOnClick(EventHandler click)
{
this.click = click;
}
public string Text { get; set; }
public void RaiseClickEvent()
{
click(this, EventArgs.Empty);
}
}
This way I was able to make stub class which have private event where I can subscribe and after that call method which fires event when needed.
精彩评论