Test events with nunit

Viewed 23599

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!

9 Answers

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.

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

}

I would just use FluentAssertions along with Nunit : https://fluentassertions.com/eventmonitoring/ it works really well. Here is an example from the docs

var subject = new EditCustomerViewModel();
using (var monitoredSubject = subject.Monitor())
{
    subject.Foo();
    monitoredSubject.Should().Raise("NameChangedEvent");
}
Related