How To Unit Test C# Event Handler Attachment – Source Allies
← 10 Tips to Prepare for an... Done The Game →

How To Unit Test C# Event Handler Attachment

02/08/2018 By Cecil Williams

I recently wanted to unit test a method that assigned a delegate to an event handler. I derived a way to use Reflection for asserting that the delegate was attached. This article explains my solution.

Note: If you are looking for information on C# events and delegates, I recommend you take a look at this video by Mosh: C# Events and Delegates Made Simple.

Normally you cannot see the delegates attached to a handler. This stackoverflow question has a good explaination of why and what your options are: c-sharp-how-to-find-if-an-event-is-hooked-up.

I also ran across a great feature request for Moq to assert an event handler for us: Moq Issue. This feature is still open and appears to be included in v4.9.0, but that version does not have a release date.

So what approach worked for me? Let me show you an example.

First, assume you have a class that implements the property changed event (example from Fody):


public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    string _givenNames;
    public string GivenNames
    {
        get { return _givenNames; }
        set
        {
            if (value != _givenNames)
            {
                _givenNames = value;
                OnPropertyChanged("GivenNames");
                OnPropertyChanged("FullName");
            }
        }
    }

    string _familyName;
    public string FamilyName
    {
        get { return _familyName; }
        set
        {
            if (value != _familyName)
            {
                _familyName = value;
                OnPropertyChanged("FamilyName");
                OnPropertyChanged("FullName");
            }
        }
    }

    public string FullName => $"{GivenNames} {FamilyName}";

    public void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

And assume you have a client of that class that needs to listen for changes:


public class PersonMonitor 
{
    public void Monitor(Person person)
    {
        ((INotifyPropertyChanged) person).PropertyChanged += PersonOnPropertyChanged;
    }

    private void PersonOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
    {
        //check property...
    }
}

Below is a unit test to assert that a delegate is attached to the PropertyChanged event when the Monitor method is invoked. First you get the type from the class that has the event. Next you get the FieldInfo for the event by name from the type. Then you get the value of the FieldInfo from the instance, cast the value as a delegate, and assert that it is not null.


[TestFixture] //using nUnit
public class PersonMonitorUnitTest
{
    [Test]
    public void TestEventHandlerAssigned()
    {
        var person = new Person();
        var personMonitor = new PersonMonitor();

        personMonitor.Monitor(person);

        VerifyDelegateAttachedTo(person, nameof(INotifyPropertyChanged.PropertyChanged));
    }

    private void VerifyDelegateAttachedTo(object objectWithEvent, string eventName)
    {
        var allBindings = BindingFlags.IgnoreCase | BindingFlags.Public | 
        BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
        
        var type = objectWithEvent.GetType();
        var fieldInfo = type.GetField(eventName, allBindings);
        
        var value = fieldInfo.GetValue(objectWithEvent);
        
        var handler = value as Delegate;
        handler.Should().NotBeNull(); //using fluent assertions
    }
}

← 10 Tips to Prepare for an... Done The Game →
Source Allies Logo © Source Allies, Inc.