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

When you are developing an application that uses events to pass messages between classes, you should unit test the events to ensure correct operation. This includes testing that a class that raises events does so as expected. It also means testing that consumers of events correctly identify that an event has been raised and react accordingly. In this article we will look at the former. A later article will discuss how you can test the reaction to events raised by dependencies.

When testing that a class raises events correctly, there are three elements to verify. Firstly, the class should raise the correct event according to the process being executed. Secondly, the event should refer to the object that raised it. Finally, any event arguments pertinent to the event should be set to the expected values. We can test all three of these items using NUnit. We will see examples using code suitable for .NET 1.1, 2.0 and 3.5, though these methods are compatible with other versions.

Code Under Test

In order to demonstrate the testing of events, we need a sample class. The Car class, shown below, is a variation upon the example in the C# Events article. It represents a car that has a speed and can accelerate. When accelerating to above the safe speed limit, an event is raised:

public class Car
{
    private int _speed = 0;
    private int _safetySpeed = 70;

    public event SpeedLimitExceededEventHandler SpeedLimitExceeded;

    public int Speed
    {
        get { return _speed; }
        set { _speed = value; }
    }

    public void Accelerate(int mph)
    {
        int oldSpeed = _speed;
        _speed += mph;

        if (oldSpeed <= _safetySpeed && _speed > _safetySpeed)
        {
            SpeedEventArgs e = new SpeedEventArgs();
            e.ExcessSpeed = _speed - _safetySpeed;
            OnSpeedLimitExceeded(e);
        }
    }

    private void OnSpeedLimitExceeded(SpeedEventArgs e)
    {
        if (SpeedLimitExceeded != null) SpeedLimitExceeded(this, e);
    }
}

The SpeedLimitExceeded event is based upon the SpeedLimitExceededEventHandler delegate. To define this delegate, add the following line of code to the namespace, outside of the class' code block.

public delegate void SpeedLimitExceededEventHandler(object source, SpeedEventArgs e);

Finally, we need to create a class for the event arguments. The SpeedEventArgs type includes a single property, which contains the excess speed of the car.

public class SpeedEventArgs : EventArgs
{
    private int _excessSpeed;

    public int ExcessSpeed
    {
        get { return _excessSpeed; }
        set { _excessSpeed = value; }
    }
}

Testing Events in .NET 1.1

When using the .NET framework 1.1, we must test the raising of events by writing a number of methods. Usually a test fixture is created containing a Setup method and one or more tests, in addition to a private method that is called when the event is raised. To begin, let's create a test fixture:

[TestFixture]
public class WhenAcceleratingToAboveTheSpeedLimit_1_1
{
}

As we will be using several methods, we need to create some class-level variables that will be accessible throughout the test fixture. We will use the four variables shown below. The _car variable will contain the Car object that we are testing.

The _eventRaised variable is a simple flag that defaults to false but will be set to true when the SpeedLimitExceeded event is processed by the event handler. The _eventSource and _eventArgs objects will be set to the values provided by the event when it is raised. The values in these three variables will be used in assertions to verify the correct operation of the Car class.

Add the following within the test fixture class.

Car _car;
bool _eventRaised;
object _eventSource;
SpeedEventArgs _eventArgs;

Now we can create the Setup method for the tests. This will contain the Arrange and Act parts of the Arrange, Act, Assert pattern. First a new Car object is created and its SpeedLimitExceeded event is attached to a new method. Next, the starting speed for the car is set. Finally, in the Act stage, the car is accelerated to a speed that should cause the event to be raised:

[SetUp]
public void Setup()
{
    _car = new Car();
    _car.SpeedLimitExceeded += new SpeedLimitExceededEventHandler(car_SpeedLimitExceeded);
    _car.Speed = 65;
    _car.Accelerate(6);
}

To complete the set up, we need to create the method that subscribes to the event. This method simply sets the _eventRaised flag and stores the source of the event and the arguments in the class-level variables.

void car_SpeedLimitExceeded(object source, SpeedEventArgs e)
{
    _eventRaised = true;
    _eventSource = source;
    _eventArgs = e;
}

We can now complete the test fixture by adding the tests that check the values of the class-level variables in Assert statements. The three tests below check that the flag is set, the source of the event is the originating Car object and the event arguments contain the correct excess speed value. These should all pass because the car has been accelerated beyond the speed limit, causing the event to be raised.

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

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

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

NB: In a real test suite you would add further tests that check the correct usage of the event in all edge case scenarios.

15 June 2011