如何对基于UI的事件进行单元测试?

时间:2014-10-31 13:24:04

标签: c# winforms unit-testing mstest

我想用MSTest编写单元测试,用于验证控制元素更改后是否调用了某个事件。不幸的是,事件处理程序下面的代码" comboBoxComPort_SelectedIndexChanged"对于comboBoxComPort(这是一个WinForms控件)永远不会被调用。这当然会导致测试代码中的匿名处理程序无法被调用。

[TestMethod()]
public void ComboBoxComPort_SelectionChanged_DirtyEventFired()
{
    ConfigUI target = new ConfigUI();
    var accessibleTarget = new PrivateObject(target);
    ComboBox comboBoxComPort = (ComboBox)accessibleTarget.GetField("comboBoxComPort");

    bool dirtyEventCalled = false;
    target.DirtyEvent += delegate
    {
        dirtyEventCalled = true;
    };

    comboBoxComPort.SelectedIndex = comboBoxComPort.Items.Count - 1;

    Assert.IsTrue(dirtyEventCalled);
}

为简单起见,我们假设这是" SelectedIndexChanged" -handler:

public class ConfigUI
{
     [...]

     private void comboBoxComPort_SelectedIndexChanged(object sender, EventArgs e)
     {
         DirtyEvent();
     }
 }

有人可以告诉我测试失败的原因吗?我知道在单元测试中访问私有成员通常不是一个好主意,但我没有看到更好的方法来测试UI行为。当然也欢迎这方面的建议。

2 个答案:

答案 0 :(得分:0)

这是您的注册处理程序吗?

 target.DirtyEvent += delegate
{
    dirtyEventCalled = true;
};

如果确实引发了事件,那么并不意味着当事件不允许“冒泡或隧道”时将调用处理程序...根据上下文,当第一个处理程序收到事件时,可以认为事件处理控制。 WPF对此概念特别挑剔,强制处理程序将ISHandled位设置为false,以使事件浮动到其他位置。

如果可以;在事件的第一个处理程序中设置断点,然后在该事件的测试中设置断点。重新启动应用程序,并首先确保第一个处理程序正在查看它。退出之前,请查看该处理程序中的事件数据。退出第一个处理程序后,如果未调用您的测试处理程序,则因为该事件被视为“满足”。这应该让你更接近找到解决方案。

答案 1 :(得分:0)

我将为ConfigUI类引入一个接口(因为你想看到一个控件在该类上调用一个方法,对吗?),然后使用Moq库在测试中模拟ConfigUI并使用Moq.Verify来看到方法被调用(你可以要求验证说多少次等等......)