Event Sequence Unit Testing – Conclusion

By , April 27, 2010 1:25 am

A lot of the development we’ve been doing here at GojiSoft has involved event driven component development. This four part article describes how we went about developing a generalized event testing framework to more easily write unit tests that codified event firing sequences.

  • Part 1 Unit testing event sequences.
  • Part 2 Developing an event monitor to test an object’s events.
  • Part 3 Using Reflection and MSIL (Intermediate Language) to implement a generic event monitor.
  • Part 4 Reflection and MSIL code for dynamic event subscription in detail.
  • Conclusion Using the EventMonitor to write [Test]s.

Download Source Code


Conclusion

In Part 1 of this series we saw some of the challenges of writing event unit tests. The challenges mainly revolved around writing lots of repetitive boilerplate code, e.g.:

[Test]
public void EventSequenceTest()
{
    bool eventARaised, eventBRaised;

    eventARaised = eventBRaised = false;

    EventPublisher publisher = new EventPublisher();

    publisher.EventA += delegate { eventARaised = true; };
    publisher.EventB += delegate { eventBRaised = true; };

    //Do some stuff to the state of publisher.
    publisher.RaiseA();
    Assert.IsTrue(eventARaised, "Event A raised.");

    //Do some stuff to the state of publisher.
    publisher.RaiseB();
    Assert.IsTrue(eventBRaised, "Event B raised.");
}

To add to the mix we saw slight variations with INotifyPropertyChanged events, and further complications with asynchronous events. This all starts getting repetitive and messy when you’ve got lots of tests to write.

In parts 2-4, we went over the gory details of implementing an event monitor which could test the events of any object, and so be used to write unit tests more easily.

So how exactly can the event monitor be used to write unit tests?

EventMonitor.Assert

The EventMonitor class has two static methods:

Assert(Action test, object publisher, IEnumerable<string> expectedSequence)

Assert(Action test, object publisher, IEnumerable<string> expectedSequence, int timeoutMS)

Where:

  • test Code which manipulates the state of the test object and causes events to be raised.
  • publisher The test object - any object that publishes events.
  • expectedSequence A list of event names in the order they are expected to be raised.
  • timeoutMS For asynchronous events, the maximum amount of time to wait for each event.

The following show examples of using the EventMonitor with: synchronous, asynchronous and INotifyPropertyChanged events. The event monitor can be used to test an object that has a mixture of these events types.

Synchronous

[Test]
public void EventTest()
{
    var publisher = new EventPublisher();

    Action test = () => { publisher.RaiseA(); publisher.RaiseB(); };

    var expectedSequence = new[] { "EventA", "EventB" };

    EventMonitor.Assert(test, publisher, expectedSequence);
}

Asynchronous

Pretty much the same as testing synchronous events, but with the edition of specifying a timeout value.

[Test]
public void EventTest()
{
    var publisher = new AsyncEventPublisher();

    Action test = () => { publisher.RaiseA(); publisher.RaiseB(); };

    var expectedSequence = new[] { "EventA", "EventB" };

    EventMonitor.Assert(test, publisher, expectedSequence, TimeoutMS);
}

INotifyPropertyChanged

For events that are published via an INotifyPropertyChanged implementation, the event name should be the name of the associated property.

[Test]
public void EventTest()
{
    var publisher = new PropertyChangedEventPublisher();

    Action test = () => { publisher.X = 1; publisher.Y = 2; };

    var expectedSequence = new[] { "X", "Y" };

    EventMonitor.Assert(test, publisher, expectedSequence);
}

Download Source Code

Leave a Reply