Unit Testing Property Change Notification

Explanation

The Caliburn.Testability assembly contains various classes related to unit testing a UI. By using Caliburn.Testability.Extensions, you can add a number of assertion methods to your objects which can be used for testing property change notification.

Note: This feature is only available to WPF.

Prerequisites

In order to correctly test WPF user interfaces, you should insure that your tests are running in an STA thread. Check the documentation for your unit testing framework to insure that your tests are configured to run properly. If your testing framework does not support this feature, take a look at this blog.

Usage

There are two extension methods that aid in testing change notification. They are AssertThatAllProperties() and AssertThatProperty(). The former makes the defined assertions on all public properties of an object while the latter asserts against a single property, defined using a lambda. Following are several examples of things that you can assert using these two extension methods.

Note: All model classes have the following base class definition:
public abstract class ChangeNotificationBase : INotifyPropertyChanged
{
    public virtual event PropertyChangedEventHandler PropertyChanged = delegate { };
 
    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Assert Correct Spelling of Property Names
public class NotificationWithWrongName : ChangeNotificationBase
{
    private string _string;

    public string RaisesWrongNotification
    {
        get { return _string; }
        set
        {
            _string = value;
            RaisePropertyChanged("Oops!");
        }
    }
}
 
[Test]
public void check_change_notifications()
{
    var sut = new NotificationWithWrongName();
 
    sut.AssertThatAllProperties().RaiseChangeNotification();
}

Notice the fluent interface allows the test code to declare what it is asserting: AssertThatAllProperties().RaiseChangeNotification. The previous test will fail because all properties do not raise the correct change notification. The property "RaisesWrongNotification" is misspelled as "Oops!" and is detected by the framework. This test would also fail if the event had not fired at all or if there were no properties on the object that fired events.

Below are examples of a few other things you can do with the provided methods.

Assert Notification for a Specific Property
public class NotificationOnAllProperties : ChangeNotificationBase
{
    private object _object;
    private string _string;
 
    public object Object
    {
        get { return _object; }
        set
        {
            _object = value;
            RaisePropertyChanged("Object");
        }
    }
 
    public string String
    {
        get { return _string; }
        set
        {
            _string = value;
            RaisePropertyChanged("String");
        }
    }
}
 
[Test]
public void check_a_single_property()
{
    var sut = new NotificationOnAllProperties();
 
    sut.AssertThatProperty(x => x.String)
        .RaisesChangeNotification();
}

Ignore A Property when Checking Change Notifications
public class PartialNotification : ChangeNotificationBase
{
    private string _notification;
 
    public string NoNotification { get; set; }
 
    public string Notification
    {
        get { return _notification; }
        set
        {
            _notification = value;
            RaisePropertyChanged("Notification");
        }
    }
}
 
[Test]
public void some_properties_can_be_ignored()
{
    var sut = new PartialNotification();
 
    sut.AssertThatAllProperties()
        .Ignoring(x => x.NoNotification)
        .RaiseChangeNotification();
}

Check Change Notifications by Setting with a Provided Value
[Test]
public void specific_values_can_be_set_on_individual_properties()
{
    var sut = new NotificationOnAllProperties();
 
    sut.AssertThatAllProperties()
        .SetValue(x => x.String, "some_string")
        .RaiseChangeNotification();
 
    Assert.That(sut.String, Is.EqualTo("some_string"));
}

Last edited Oct 23, 2009 at 6:56 PM by EisenbergEffect, version 6