Test events with nunit

I'm just starting with TDD and could solve most of the problems I've faced on my own. But now I'm lost: How can I check if events are fired? I was looking for something like Assert.Raise or Assert.Fire but there's nothing. Google was not very useful, most of the hits were suggestions like foo.myEvent += new EventHandler(bar); Assert.NotNull(foo.myEvent); but that proves nothing.

Thank you!

Answers


Checking if events were fired can be done by subscribing to that event and setting a boolean value:

var wasCalled = false;
foo.NyEvent += (o,e) => wasCalled = true;

...

Assert.IsTrue(wasCalled);

Due to request - without lambdas:

var wasCalled = false;
foo.NyEvent += delegate(o,e){ wasCalled = true;}

...

Assert.IsTrue(wasCalled);

I prefer to do as follows:

var wait = new AutoResetEvent(false);
foo.MeEvent += (sender, eventArgs) => { wait.Set(); };
Assert.IsTrue(wait.WaitOne(TimeSpan.FromSeconds(5)));

Advantages: Supports multithreading scenario (if handler is invoked in different thread)


If you know the event will be fired synchronously:

bool eventRaised = false;
Customer customer = new Customer() { Name = "Carl" };
customer.NameChanged += (sender, e) => { eventRaised = true; };

customer.Name = "Sam";

Assert.IsTrue(eventRaised);

If the event may be fired asynchronously:

ManualResetEvent eventRaised = new ManualResetEvent(false);
Customer customer = new Customer() { Name = "Carl" };
customer.NameChanged += (sender, e) => { eventRaised.Set(); };

customer.Name = "Sam";

Assert.IsTrue(eventRaised.WaitOne(TIMEOUT));

However, some say testing asynchronous behavior should be avoided.


I recently had to do this, and below is what I came up with. The reason I did not do what the other posts said, is I do not like the idea of a variable keeping state and having to reset it "manually" between multiple events.

Below is the code of the ClassUnderTest with NameChanged event that is tested in MyTests tests:

public class ClassUnderTest {
    private string name;
    public string Name {
        get { return this.name; }
        set {
            if (value != this.name) {
                this.name = value;
                NameChanged(this, new PropertyChangedEventArgs("Name"));
            }
        }
    }

    public event EventHandler<PropertyChangedEventArgs> NameChanged = delegate { };
}

[TestFixture]
public class MyTests {
    [Test]
    public void Test_SameValue() {
        var t = new ClassUnderTest();
        var e = new EventHandlerCapture<PropertyChangedEventArgs>();
        t.NameChanged += e.Handler;

        Event.Assert(e, Event.IsNotRaised<PropertyChangedEventArgs>(), () => t.Name = null);
        t.Name = "test";
        Event.Assert(e, Event.IsNotRaised<PropertyChangedEventArgs>(), () => t.Name = "test");
    }
    [Test]
    public void Test_DifferentValue() {
        var t = new ClassUnderTest();
        var e = new EventHandlerCapture<PropertyChangedEventArgs>();
        t.NameChanged += e.Handler;

        Event.Assert(e, Event.IsPropertyChanged(t, "Name"), () => t.Name = "test");
        Event.Assert(e, Event.IsPropertyChanged(t, "Name"), () => t.Name = null);
    }
}

The supporting classes are below. The classes can be used with any EventHandler<TEventArgs> or expanded to other delegates. Event tests can be nested.

/// <summary>Class to capture events</summary>
public class EventHandlerCapture<TEventArgs> where TEventArgs : EventArgs {
    public EventHandlerCapture() {
        this.Reset();
    }

    public object Sender { get; private set; }
    public TEventArgs EventArgs { get; private set; }
    public bool WasRaised { get; private set; }

    public void Reset() {
        this.Sender = null;
        this.EventArgs = null;
        this.WasRaised = false;
    }

    public void Handler(object sender, TEventArgs e) {
        this.WasRaised = true;
        this.Sender = sender;
        this.EventArgs = e;
    }
}

/// <summary>Contains things that make tests simple</summary>
public static class Event {
    public static void Assert<TEventArgs>(EventHandlerCapture<TEventArgs> capture, Action<EventHandlerCapture<TEventArgs>> test, Action code) where TEventArgs : EventArgs {
        capture.Reset();
        code();
        test(capture);
    }
    public static Action<EventHandlerCapture<TEventArgs>> IsNotRaised<TEventArgs>() where TEventArgs : EventArgs {
        return (EventHandlerCapture<TEventArgs> test) => {
            NUnit.Framework.Assert.That(test.WasRaised, Is.False);
        };
    }
    public static Action<EventHandlerCapture<PropertyChangedEventArgs>> IsPropertyChanged(object sender, string name) {
        return (EventHandlerCapture<PropertyChangedEventArgs> test) => {
            NUnit.Framework.Assert.That(test.WasRaised, Is.True);
            NUnit.Framework.Assert.That(test.Sender, Is.SameAs(sender));
            NUnit.Framework.Assert.That(test.EventArgs.PropertyName, Is.EqualTo(name));
        };
    }
}

Not really done this myself, but maybe you could add a dummy event handler to the event you wanna subscribe to and have it update a local boolean variable so that after the method is fired you can check the state of that boolean to see if the event was fired?

Something like:

bool eventFired = false;
foo.MyEvent += (s, e) => { eventFired = true };

Assert.IsTrue(eventFired);

@theburningmonk: A ";" is missing. Corrected version is:

bool eventFired = false;
foo.MyEvent += (s, e) => { eventFired = true; };
Assert.IsTrue(eventFired);

Cheers! ;-)


Using NUnit and Moq you can do more robust event testing.

Mock Class used to monitor event triggers:

public class AssertEvent { public virtual void Call(string obj) { } }
Mock<AssertEvent> EventMock;
AssertEvent Evt;

Setup for event Triggers:

[SetUp]
public void TestInit() {
    EventMock = new Mock<AssertEvent>();
    Evt= EventMock.Object;
}

Using Mock Objects in Tests:

[Test]
public void TestMethod() {
    myObject.Event1 += (sender, args) => Evt.Call("Event1Label");
    myObject.Event2 += (sender, args) => Evt.Call("Event2Label");
    myObject.Event3 += (sender, args) => Evt.Call("Event3Label");        

    myObject.SomeEventTrigger();

    EventMock.Verify(m => m.Call("Event1Label"), Times.Exactly(1));
    EventMock.Verify(m => m.Call("Event2Label"), Times.Never());
    EventMock.Verify(m => m.Call("Event3Label"), Times.Between(1,3);

}

You can add your custom event handler which, for example, increments some integer field in test case class. And then check if field was incremented.


Need Your Help

How to load all files in a directory using webpack without require statements

javascript build webpack

I have a large amount of javascript files split into 4 subdirectory in my app. In grunt I grab all of them and compile them into one file. These files do not have a module.exports function.