[Tip Jar] Unit Test Events With Anonymous Delegates
Here we are already looking ahead to learn about the language features of C# 3.0 and I am still finding new ways to make my code better with good “old fashioned” C# 2.0.
Like many people, I tend to fall into certain habits of writing code. For example, today I was writing a unit test to test the source of a particular event. I wanted to make sure that the event is raised and that the event arguments were set properly. Here’s the test I started off with (some details changed for brevity) which reflects how I would do this in the old days.
private bool eventRaised = false;
[Test]
public void SettingValueRaisesEvent()
{
Parameter param = new Parameter("num", "int", "1");
param.ValueChanged += OnValueChanged;
parameter.Value = "42"; //should fire event.
Assert.IsTrue(eventRaised, "Event was not raised");
}
void OnValueChanged(object sender, ValueChangedEventArgs e)
{
Assert.AreEqual("42", e.NewValue);
Assert.AreEqual("1", e.OldValue);
Assert.AreEqual("num", e.ParameterName);
eventRaised = true;
}
A couple of things rub me the wrong way with this code.
First, I do not like relying on the member variable eventRaised
because another test could inadverdently set that value, unless I make
sure to reset it in the SetUp
method. So now I need a SetUp
method.
Second, I don’t like the fact that this test requires this separate
event handler method, OnValueChanged
. Ideally, I would prefer that the
unit test be self contained as much as possible.
Then it hits me. Of course! I should use an anonymous delegate to handle that event. Here is the revised version.
[Test]
public void SettingValueRaisesEvent()
{
bool eventRaised = false;
Parameter param = new Parameter("num", "int", "1");
param.ValueChanged +=
delegate(object sender, ValueChangedEventArgs e)
{
Assert.AreEqual("42", e.NewValue);
Assert.AreEqual("1", e.OldValue);
Assert.AreEqual("num", e.ParameterName);
eventRaised = true;
};
param.Value = "42"; //should fire event.
Assert.IsTrue(eventRaised, "Event was not raised");
}
Now my unit test is completely self-contained in a single method. Lovely!
In general, I try not to use anonymous delegates all over the place, especially delegates with a lot of code. I think they can become confusing and hard to read. But this is a situation in which I think using an anonymous delegate is particularly elegant.
Contrast this approach to the approach using Rhino Mocks I wrote about a while ago. In that scenario, I was testing that a subscriber to an event handles it properly. In this case, I am testing the event source.
Comments
0 responses