Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing WinForms MVP and Event mechanism with moq

Tags:

c#

mvp

winforms

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 view;

        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.

like image 444
Vajda Avatar asked Nov 20 '25 01:11

Vajda


2 Answers

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.

like image 120
Gert Arnold Avatar answered Nov 22 '25 15:11

Gert Arnold


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.

like image 32
Vajda Avatar answered Nov 22 '25 15:11

Vajda