In WPF work, it is very common to work with implementations of INotifyPropertyChanged. We need support for change notification in order to bind to the UI, and this interface is frequently the best approach. This means I have lots of properties that look like this:
public string FirstName
{
get { return _firstName;}
set
{
_firstName = value;
RaisePropertyChanged("FirstName");
}
}
I've gone back and forth as to whether or not I should test these properties for change notification on properties. My main argument for not doing it, is the ROI. The typical test pattern might look something like this:
[Test]
public void FirstName_raises_change_notification()
{
bool has_property_changed = false;
_person.PropertyChanged +=
(s, e) => { if (e.PropertyName == "FirstName") has_property_changed = true; };
_person.FirstName = "new_name";
Assert.That(has_property_changed);
}
Sure, this isn't a long test, but when you consider the number of properties I could be dealing with you'll see the potential for a lot of noise.
I also don't like the fact that I have yet another string in my code; easy to miss when refactoring. Nevertheless, I feel like I ought to have test coverage for these change notifications.
What's the solution? Make change notification easier to test.
Step One
I extracted out the test pattern into an extension method that applies to INotifyPropertyChanged. So my test now looks like this:
[Test]
public void FirstName_raises_change_notification()
{
_person.AssertThatPropertyRaisesChangeNotification(
() => _person.FirstName);
}
By using an expression to identify the property, I removed the magic string. I also have an overload if I need to set the property to a specific value:
[Test]
public void FirstName_raises_change_notification()
{
_person.AssertThatPropertyRaisesChangeNotification(
() => _person.FirstName, "new_name");
}
The code for the extension is this:
public static class AssertExtensions
{
public static void AssertThatPropertyRaisesChangeNotification<T, K>(
this T propertyOwner,
Expression<Func<K>> property,
K valueToSet) where T : INotifyPropertyChanged
{
var has_property_changed = false;
var memberExpression = (MemberExpression) property.Body;
var propertyInfo = (PropertyInfo) memberExpression.Member;
propertyOwner.PropertyChanged +=
(s, e) => { if (e.PropertyName == propertyInfo.Name) has_property_changed = true; };
propertyInfo.SetValue(propertyOwner, valueToSet, null);
if (has_property_changed) return;
var msg =
string.Format(
"The property, {0}, did not raise change notification.\n" +
"The property was set to '{1}'.\nThe property is owned by {2}",
propertyInfo.Name,
valueToSet,
typeof (T).Name);
throw new AssertionException(msg);
}
public static void AssertThatPropertyRaisesChangeNotification<T, K>(
this T propertyOwner,
Expression<Func<K>> property) where T : INotifyPropertyChanged
{
propertyOwner.AssertThatPropertyRaisesChangeNotification(property, default(K));
}
}
Step Two
The next step (which I haven't done yet) would be to provide a fluent API for easily expressing which classes and properties I care about. With the extension above, I'm still just dealing with one property at a time.
What I would like is a way to say "all public properties on class X, except Y & Z" or perhaps "only properties Y & Z on class X". Then I can have concise, descriptive, intent-revealing tests regarding change notification.
Thoughts? Improvements?
Posted
11-13-2008 3:43 PM
by
Christopher Bennage