简体   繁体   中英

Hooking up to an event within unit test

I'm trying to run a unit test on a class that does some stuff on a separate thread and then notifies the parent that it has finished the task using an eventhandler. This is my test code:

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

        }
    }

And this is the method I am testing:

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

I realize that Init() doesn't use a new thread, but I'm just trying to make sure the test is running now. Instead of passing, the test just gets stuck in the while() loop forever, and the anonymous delegate is never entered.

Is the event hooked up incorrectly? Can events be used like this in Unit tests?

Assert does not stop the test, and tests do not fail if an Assert statement is not executed - so the while(true) loop keeps your test from finishing.

Furthermore events behave like simple method calls - so before target.Init(); returns, the event has already occurred.

You should probably use a variable bool eventOccurredAndSucceeded = false which you can set in the event handler, and simply test it after calling 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);
    }

Events can be tested, but the best way I've found is using the ManualResetEvent . Consider this modification:

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

What happens here is the WaitOne will stop this methods execution waiting for the Set() to be called. Since the Set() gets called inside the event handler, it waits logically until the event is raised and asserted.

However, you're going to have to move your Assert outside the event handler because the method won't succeed otherwise, so there is one more slight modification required:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM