在单元测试中连接到一个事件

时间:2013-12-17 15:06:25

标签: c# unit-testing events testing event-handling

我正在尝试对一个在单独线程上执行某些操作的类运行单元测试,然后使用eventhandler通知父级已完成任务。这是我的测试代码:

        [TestMethod()]
    public void InitTest()
    {
        Controller target = new Controller();
        target.FinishedCommand += delegate(bool success)
        {
            Assert.AreEqual(true, success);
        };
        target.Init();
        while (true)
        {

        }
    }

这是我正在测试的方法:

public delegate void ControllerEventHandler(bool success);
public class Controller
{
    public event ControllerEventHandler FinishedCommand;
    public void Init()
    {
        FinishedCommand(true);
    }
}

我意识到Init()不使用新线程,但我只是想确保测试现在正在运行。测试只是永远停留在while()循环中,而不是传递,而且永远不会输入匿名委托。

事件是否错误连接?在单元测试中可以像这样使用事件吗?

2 个答案:

答案 0 :(得分:2)

Assert不会停止测试,如果没有执行Assert语句,测试也不会失败 - 因此while(true)循环可以防止测试结束。

此外,事件的行为类似于简单的方法调用 - 因此在target.Init();返回之前,事件已经发生。

您应该使用可以在事件处理程序中设置的变量bool eventOccurredAndSucceeded = false,并在调用target.Init();后进行测试:

    [TestMethod()]
    public void InitTest()
    {
        bool eventOccurredAndSucceeded = false;
        Controller target = new Controller();
        target.FinishedCommand += delegate(bool success)
        {
            if (success)
            {
                eventOccurredAndSucceeded = true;
            }
        };

        target.Init();
        Assert.AreEqual(true, eventOccurredAndSucceeded);
    }

答案 1 :(得分:1)

可以测试事件,但我发现的最好方法是使用ManualResetEvent。考虑这个修改:

public void InitTest()
{
    Controller target = new Controller();
    target.FinishedCommand += delegate(bool success)
    {
        Assert.AreEqual(true, success);
        eventRaised.Set();
    };

    ManualResetEvent eventRaised = new ManualResetEvent(false);
    target.Init();

    eventRaised.WaitOne();
}

这里发生的是WaitOne将停止此方法执行,等待Set()被调用。由于Set()在事件处理程序内部被调用,因此它会在逻辑上等待,直到事件被引发并声明为止。

但是,您必须将Assert移到事件处理程序之外,因为该方法不会成功,因此还需要进行一些修改:

public void InitTest()
{
    bool succeeded = false;
    Controller target = new Controller();
    target.FinishedCommand += delegate(bool success)
    {
        succeeded = success;
        eventRaised.Set();
    };

    ManualResetEvent eventRaised = new ManualResetEvent(false);
    target.Init();

    eventRaised.WaitOne();
    Assert.IsTrue(succeeded);
}