Поделиться через


Testing Events Using Anonymous Methods

If you are unit testing a class which may raise an event, it will be appropriate to test that the event is raised when appropriate. Before .NET 2.0, you had to attach an event handler to an instance of the class to test the event, but now you can do it with anonymous methods.

This is probably best illustrated by an example. Imagine that you are developing the following class:

 public class MyEventRaiser
 {
     public event EventHandler MyEvent;
  
     public void Raise()
     {
         if (this.MyEvent != null)
         {
             this.MyEvent(this, EventArgs.Empty);
         }
     }
 }

You must excuse the simplicity of the example; the only thing this class really does is raise an event.

In .NET 1.1, the best way you could test if the event was actually raised was like this:

 private bool eventWasRaised_;
  
 [TestMethod]
 public void WithoutAnonymousMethod()
 {
     this.eventWasRaised_ = false;
  
     MyEventRaiser eventRaiser = new MyEventRaiser();
     eventRaiser.MyEvent += 
         new EventHandler(eventRaiser_MyEvent);
  
     eventRaiser.Raise();
  
     Assert.IsTrue(this.eventWasRaised_);
 }
  
 private void eventRaiser_MyEvent(object sender, EventArgs e)
 {
     this.eventWasRaised_ = true;
 }

As you can tell, it's necessary to create three members of the unit test class to perform a single test:

  • A private member variable to track whether the event was raised.
  • The test method itself.
  • An event handler method.

Personally, I feel that each unit test should be completely contained within its own test method if at all possible, and testing events like this violates that principle. In my simple example, this doesn't seem so bad, but as you write more tests, things get more complicated: You need to reset all your member variables for each test, since tests should be indpendent, etc.

Luckily, .NET 2.0 includes support for anonymous methods, so you can now rewrite the test:

 [TestMethod]
 public void WithAnonymousMethod()
 {
     bool eventWasRaised = false;
  
     MyEventRaiser eventRaiser = new MyEventRaiser();
     eventRaiser.MyEvent += 
         delegate(object sender, EventArgs e) {
             eventWasRaised = true;
         };
  
     eventRaiser.Raise();
  
     Assert.IsTrue(eventWasRaised);
 }

This is much simpler, and follows the principle that each unit test should be self-contained. There are no member variables or external event handler methods involved. The code is more compact, and I find it more readable, too. You can even do Asserts in the anonymous method, if you need to validate the EventArgs, etc.

Comments

  • Anonymous
    June 27, 2006
    Generally, wouldn't you encapsulate the raising of events, through the use of a protected method, such as DoRaiseEvent(object sender, EventArgs e)??  I know you're trying to illustrate a point here, but certainly I don't generally expose a public method to raise events, only a protected one.  If that's the case, then you would need to write a stub to handle this, wouldn't you, or use mock objects.  I like the point you're trying to make, unfortunately it requires the same simplistic code to make it work, doesn't it?
    Do you have ways around doing this with a properly encapsulated class at all?

    Cheers.

  • Anonymous
    June 28, 2006
    Martin, thank you for your comment.

    Perhaps the example has become a victim of being too simplistic, but fortunately, the method illustrated works well in production-grade code as well.

    You are correct that I would rarely (if at all) expose a public method whose sole responsibility would be to raise events. Raising events is most correctly done using a protected method as you suggest (see e.g. my related post http://blogs.msdn.com/ploeh/archive/2006/03/17/oneventCodeSnippet.aspx).

    However, this does not preclude me from testing that some (other) public method can raise an event. Imagine that, instead of the Raise method, I also had a DoStuff(int) method, and I wanted to test that if the parameter was less than 10, the event would be raised. In this case, I'd do something very similar: Hook up the event to the anonymous method; call the DoStuff method with a value of e.g. 7; and then assert that the event was raised.

    In another test case, I might then call DoStuff with a value of 11 and validate that the event was not raised, again using an anonymous method.

    How the test target actually raises the event is an implementation detail that is slightly orthogonal to my original point, but using a protected virtual method is the recommended way.

    I hope this answers your question - if not, I'll be happy to provide a slightly more realistic example.

  • Anonymous
    August 02, 2006
    I'm interested how you'd approach the situation, if for example, you have an interface which describes a set of UI events, and a set of setter properties, so that we are informed of and have the ability to set information in the UI using the interface.
    Hopefully, in that case, you wouldn't code so that you'd make you protected Do{EventName} methods public, would you?
    The only way I can think of to achieve this would be to create a stub object that implements the interface. Perhaps would be a good idea to point out the pros and cons of the approach??  Good information though.

  • Anonymous
    August 02, 2006
    Hi Martin

    The normal pattern for raising events is to use a protected method, and I wouldn't recommend making such a method public. Visual Studio Code Analysis (or FxCop) would also complain about such a method.

    If I understand your scenario correctly, you have an interface that contains, let's for simplicity's sake say, one property and one event. So you want to test that when you change the property value, you want the event to be raised? Obviously, you can't unit test an interface, since you need to have an implementation, and a stub implementation which raises the correct events in no way guarantees that any other implementation will do the same. An interface cannot enforce this kind of contract, but a base class can (see Krzysztof Cwalinas post about the subject at http://blogs.msdn.com/kcwalina/archive/2004/10/24/246947.aspx), so maybe you are trying to do something which can't be done?

    However, I'm not sure I understand your particular scenario, but maybe you could post some example code which would clarify things a bit? If it's too cumbersome to post in a comment here, you are welcome to send me an email using the Email link on my blog page. If your problem is sufficiently twisted, I may even make a new blog post out of it :)

  • Anonymous
    August 03, 2006
    The scenario is such that I have an interface for a view on the UI, that raises events when things change, and can have values set on that interface which in turn effects the UI.  I then have another class that have the implementation for the UI that is invoked when the events on the View are raised, and in turn sets values again on the view to change the UI.  What I wanted to know was how you might test such a setup, since the UI would have the private or protected methods to raise the events, and thus would not be accessible.  My approach has been to implement the view as a stubbed class that also adds the ability to raise the events, from which I am able to achieve what I wanted.  I was interested if you had some other way of achieving this also?

  • Anonymous
    August 03, 2006
    So basically you want to test that the views raise events? If this is the case, you'll have to write test code to provoke that an event is raised.

    How to do so should be part of your functional specification. This comes back to the old controversy that you should only test against the public API of your unit (see this article for a discussion of this topic: http://msdn.microsoft.com/msdnmag/issues/06/01/UnitTesting/default.aspx), so you should also be able to do something to your public API that causes the event in question to be raised. If you can't, under any circumstance, provoke the event to be raised using your public API, it sounds like you have unreachable code.

    I have probably still not correctly understood your scenario, but currently I see no reason to stub out anything to test that an event can be raised correctly. I hope this answers your question, but if not, maybe you could provide me with a small code example that illustrates your scenario?

  • Anonymous
    August 06, 2006
    You do partially understand what I'm alluding to.

    My solution to this problem was to use a view interface, which the UI implements, and then create a stub class that implements the view interface, and also some public methods to raise the events and sense the set values as properties, thus allowing my code to stay encapsulated.  I can then raise the events, and can attach my view using DI to test out the class that has the real logic in it, without having to change it.  As we've been talking, I've been developing, and this pattern is working out really nicely, and gets around the problems we have been talking about.  Thank you for the discussion!!

  • Anonymous
    August 06, 2006
    Good to hear it's working out for you now :)

    I'm happy to be of service, so don't hold off if you have other questions.

  • Anonymous
    October 25, 2006
    Mark Seemann recently published a great post demonstrating the use of anonymous methods in unit testing

  • Anonymous
    November 04, 2006
    I've not used anonymous methods too much when coding, but I ran upona (what I think is) great use

  • Anonymous
    November 04, 2006
    I've not used anonymous methods too much when coding, but I ran upon a (what I think is) great use