Shaun Xu

The Sheep-Pen of the Shaun


News

logo

Shaun, the author of this blog is a semi-geek, clumsy developer, passionate speaker and incapable architect with about 10 years’ experience in .NET and JavaScript. He hopes to prove that software development is art rather than manufacturing. He's into cloud computing platform and technologies (Windows Azure, Amazon and Aliyun) and right now, Shaun is being attracted by JavaScript (Angular.js and Node.js) and he likes it.

Shaun is working at Worktile Inc. as the chief architect for overall design and develop worktile, a web-based collaboration and task management tool, and lesschat, a real-time communication aggregation tool.

MVP

My Stats

  • Posts - 122
  • Comments - 553
  • Trackbacks - 0

Tag Cloud


Recent Comments


Recent Posts


Archives


Post Categories


Image Galleries


.NET


 

Last several weeks I was writing some unit test codes against a legacy class. This class was designed as a static class without any tests. When I tried to add test codes I found as it's a static class, some status was remained when some test methods were invoked, which might failed some following methods. So I need to reset all status (public and private) before each test methods.

 

If the status was stored in public properties of this static class, it should be very easy to reset. Just set NULL to this property in a method with TestInitialize attribute. It should be easy as well if I need to reset some status stored in private variants. We can use .NET Reflection to set NULL to them, some codes like below.

   1: var field = typeof(MyStaticClass).GetField("_privateVariant", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
   2: field.SetValue(null, new InstanceOfThisPrivateVar());

But if we need to verify the static event handlers' behaviors this might be a little bit difficult. For example in the first test I was to check an event should be raised with proper event argument. So I added a event handler function and some assert codes inside.

   1: MyStaticClass.AStaticEvent += (sender, e) =>
   2: {
   3:     Assert.IsNotNull(e);
   4:     Assert.AreEqual("Exptected value", e.SomeValue);
   5: };

While in the next test I'd like to verify the event argument should equal to another value in another scenario.

   1: MyStaticClass.AStaticEvent += (sender, e) =>
   2: {
   3:     Assert.IsNotNull(e);
   4:     Assert.AreEqual("Another expected value", e.SomeValue);
   5: };

If I run these two tests one by one separately, each of them should be passed. But if I ran them in one batch, one of them should be failed. This was because, when I ran them in one batch and when the first test was executed, it added its delegate to the event and performed assert code.

image

But when the second test was executed, the event handler delegate defined in the first test still connected with the event. Then the second event handler will be added. Then when this event was fired both of them are triggered, the first handler will be failed.

image

The solution is to remove all event handlers against this event but this is not easy if we don't want to store all event handlers in another place. After about 2 days research and found the solution on how to remove event handlers from a particular event through Reflection. The code is very simple.

   1: public static void RemoveAllEventHandlers(this Type self)
   2: {
   3:     foreach (var ei in self.GetEvents(AllBindingFlags))
   4:     {
   5:         var declaringType = ei.DeclaringType;
   6:         var field = declaringType.GetField(ei.Name, AllBindingFlags);
   7:         if (field != null)
   8:         {
   9:             var del = field.GetValue(null) as Delegate;
  10:             if (del != null)
  11:             {
  12:                 foreach (var sub in del.GetInvocationList())
  13:                 {
  14:                     ei.RemoveEventHandler(null, sub);
  15:                 }
  16:             }
  17:         }
  18:     }
  19: }

This extension method will remove all delegates registered on every static event handlers.

   1: typeof(MyStaticClass).RemoveAllEventHandlers();

And if you like you can add some condition codes to filter events by name to remove handlers against particular events.

 

Hope this helps,

Shaun

All documents and related graphics, codes are provided "AS IS" without warranty of any kind.
Copyright © Shaun Ziyan Xu. This work is licensed under the Creative Commons License.