使用moq测试WinForms MVP和事件机制

3

我在我的应用程序中使用了MVP模式。但是我在测试点击按钮后调用的方法时遇到了问题。以下是代码:

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";
        }
    }

问题在于我不知道如何编写测试,以便调用我的ButtonClick方法。我尝试了这样做:

问题在于我不知道如何编写测试,以便调用我的ButtonClick方法。我尝试了这样做:

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

我认为问题出在这一行:

this.view.Button1.Click += ButtonClick;

似乎Click事件不能记住ButtonClick方法。如何使Click成为正常工作的存根。 欢迎任何建议。 提前致谢。 问候, Vajda
编辑:当我在我的IButton接口中创建SubscribeOnClick(EventHandler click)方法而不是event EventHandler Click时,我就能够做到这一点。我还创建了一些ButtonMock,记住了方法。但是,如果有人知道更好的解决方案,请与我分享。
2个回答

1
我把我的IButton接口改成了这个:
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);
        }
    }

通过这种方式,我能够创建一个存根类,其中包含私有事件,我可以订阅该事件,然后调用方法,在需要时触发事件。


1
也许在这里使用命令模式并不是一个坏主意。你的IView非常具体实现,因为它有一定数量的控件应该有一个Click事件(我知道这只是一个例子,但还是...)。
命令模式的一个简单实现是让IView拥有一个由Presenter提供的List<Action>,并让特定的视图实现决定如何触发这些操作,例如通过执行:
this.button1.Click += (sender, e) => this.Actions[0]();

一个模拟对象不需要有 Click 事件(可能甚至不被 Moq 支持,我不确定)。你只需要让它触发其中的一个动作就行了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接