BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Testing
.NET 1.1+

Unit Testing Raised Events

Many classes use events to allow messages to be passed to other classes in a loosely coupled manner. When creating unit tests for classes that use events, the raising of those events and the arguments generated should be verified.

Testing Events in .NET 2.0

If you are using .NET 2.0 or later, you can replace the method that receives the event notifications with an anonymous method. This allows the entire set up process to exist within a single test method. The code below is equivalent to the first test fixture:

[TestFixture]
public class WhenAcceleratingToAboveTheSpeedLimit_2_0
{
    Car _car;
    bool _eventRaised;
    object _eventSource;
    SpeedEventArgs _eventArgs;

    [SetUp]
    public void Setup()
    {
        _car = new Car();
        _car.SpeedLimitExceeded += delegate(object source, SpeedEventArgs e)
        {
            _eventRaised = true;
            _eventSource = source;
            _eventArgs = e;
        };
        _car.Speed = 65;
        _car.Accelerate(6);
    }

    [Test]
    public void TheSpeedLimitExceededEventIsRaised()
    {
        Assert.IsTrue(_eventRaised);
    }

    [Test]
    public void TheCarIsTheSourceOfTheEvent()
    {
        Assert.AreSame(_car, _eventSource);
    }

    [Test]
    public void TheExcessSpeedIsCorrect()
    {
        Assert.AreEqual(1, _eventArgs.ExcessSpeed);
    }
}

The .NET 2.0 version shown above is marginally simpler than the .NET 1.1 version. However, the addition of the anonymous method gives the possibility to simplify further, if you like to use multiple assertions within a single test. As there is now no need to share variables between the set up method and the method that subscribes to the event, we can remove the setup method completely and place the class-level variables and all of the code into a single test method. This is shown in the code below. I have added comments to show the arrange, act and assert parts of the test.

[TestFixture]
public class WhenAcceleratingToAboveTheSpeedLimit_2_0_NoSetup
{
    [Test]
    public void TheSpeedLimitExceededEventIsRaisedWithTheCorrectParameters()
    {
        // Arrange
        bool eventRaised = false;
        object eventSource = null;
        SpeedEventArgs eventArgs = null;
        Car car = new Car();
        car.SpeedLimitExceeded += delegate(object source, SpeedEventArgs e)
        {
            eventRaised = true;
            eventSource = source;
            eventArgs = e;
        };
        car.Speed = 65;

        // Act
        car.Accelerate(6);
            
        // Assert
        Assert.IsTrue(eventRaised);
        Assert.AreSame(car, eventSource);
        Assert.AreEqual(1, eventArgs.ExcessSpeed);
    }
}

Testing Events in .NET 3.5

For the final sample we'll upgrade to .NET 3.5 or later. This time the anonymous method is replaced with a lambda expression. This adds only a small amount of simplification over the previous example due to the more concise syntax:

[TestFixture]
public class WhenAcceleratingToAboveTheSpeedLimit_3_5_NoSetup
{
    [Test]
    public void TheSpeedLimitExceededEventIsRaisedWithTheCorrectParameters()
    {
        // Arrange
        bool eventRaised = false;
        object eventSource = null;
        SpeedEventArgs eventArgs = null;
        Car car = new Car();
        car.SpeedLimitExceeded += (s, e) => 
        {
            eventRaised = true;
            eventSource = s;
            eventArgs = e;
        };
        car.Speed = 65;

        // Act
        car.Accelerate(6);

        // Assert
        Assert.IsTrue(eventRaised);
        Assert.AreSame(car, eventSource);
        Assert.AreEqual(1, eventArgs.ExcessSpeed);
    }
}
15 June 2011