Simplify your unit test code with some C# anonymous methods

While writing some
unit test to check that an event was indeed triggered, I figured out that
anonymous methods can be a great help to avoid writing some mock handler
methods.

Here is the case. I
have a class Foo that implements the System.ComponentModel.INotifyPropertyChanged
interface. This interface has just one event, PropertyChanged, that will let
its handlers know about the name of the property of Foo that have changed.
Basically, my unit test looks like:

 

[Test]

public void
Test_ModifyReport_NotifyPropertyChanged() {

   int nbProp1Changed
= 0;

   int nbProp2Changed
= 0;

   // …

 

   Foo foo = new Foo();

 

   foo.PropertyChanged +=

      delegate(object sender,

               PropertyChangedEventArgs
propertyChangedEventArgs) {

      Debug.Assert(sender
== project);

      switch (propertyChangedEventArgs.PropertyName)
{

         case Constants.PROPERTY1_NAME:

            nbProp1Changed ++; return;

         case Constants.PROPERTY2_NAME:

            nbProp2Changed ++; return;

         // …

      }

   };

 

   Assert.IsTrue(Foo.Prop1 != 3);

   Assert.IsTrue(nbProp1Changed == 0);

   Foo.Prop1 = 3;

   Assert.IsTrue(nbProp1Changed == 1);

 

   // Test PropertyChanged not triggered when
the value is the same

   Foo.Prop1 = 3;

   Assert.IsTrue(nbProp1Changed == 1);

   //…

}

Of course, if you
have a large number of properties, you could create a dictionary of ‘Number of
times the property X has been changed
’ indexed by ‘The property X name’.

The beauty of this trick
is that it avoids creating some handlers method and corresponding field state
to check that an event is triggered. Actually, this code is much more tricky than
it looks like at first glance. Under the hood, the C# compiler is creating a dedicated
class to hold the nbXXXChanged value (see with Reflector).  We say that the states nbXXXChanged have been
captured by the anonymous method. We are then talking with a functional
programming vocabulary because in fact we created what is named a closure in
the functional world.

I won’t go into the details of anonymous
method compilation and closure because I described all this in an article
published on TSS.NET 3 years ago (read it here). You can also read the second
part of the article about the yield keyword here.

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • VekiPeki

    After attaching an anonymous handler to the event, you cannot detach it afterwards. Or is there a way?

    I am asking this because for every event attaching code (+=) I always add some code to detach it (-=) during disposing, otherwise GC holds the references to those classes, occupying memory when it should be released.

    Of course, the stated idea IS to use it only for unit testing, not in “real life” :) .