1

I know we shouldn´t care if an eventhandler was registered for an event from outside that event, as seen here for instance How to determine if an event is already subscribed

Thus I have some code within the events-accessor to prevent any users of my API bothering about if or if not they already registered the handler:

private EventHandler foo;
public event EventHandler Foo
{
    add
    {
        if (foo == null || !foo.GetInvocationList().Contains(value))
        {
            foo += value;
        }
    }
    remove
    {
        foo -= value;
    }
}

Now I want to write a test to verify that this check works correct:

[Test]
public void MyTest()
{
    myInstance.Foo += DoSomething;
    myInstance.Foo += DoSomething;
}
void DoSomething(object sender, EventArgs args) { ... }

But how do I check if foo contains only a single handler, not two? Should I use reflection on foo to get its invocation-list or is there any better way?

MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
  • Have `DoSomething` count the number of times its invoked. Raise the `Foo` event, and assert that `DoSomething` was executed only once. If it helps, perhaps declare `DoSomething` as a local method/delegate and take advantage of closure to easily count a variable without having to add a field/state to your testing class. – Chris Sinclair Feb 09 '18 at 15:27
  • I have a rule: "Few things are more stupid then code that tries to be smart". Your are trying to do something smart, where nothing is needed. When somebody registers the same eventhandler twice, that is their own damn fault. They can unregister the events how they see fit. Having the same handler more then once might even be wanted by the user in odd circumstances. – Christopher Feb 09 '18 at 15:28
  • @ChrisSinclair How can I do this from my testclass? I just get `the event Foo can only appear on the left side of += or -=`. – MakePeaceGreatAgain Feb 09 '18 at 15:34
  • @HimBromBeere: I posted an answer. I think given your comment/question though, you may need to expose some way of raising `Foo` (which I expect makes sense.) – Chris Sinclair Feb 09 '18 at 15:37

1 Answers1

1

Have DoSomething count the number of times its invoked. Raise the Foo event, and assert that DoSomething was executed only once.

[Test]
public void MyTest()
{
    int invokeCount = 0;
    EventHandler handler = (object sender, EventArgs args) => invokeCount++;

    myInstance.Foo += handler;
    myInstance.Foo += handler;

    myInstance.SomeMethodThatRaisesFoo();

    Assert.AreEqual(1, invokeCount);
}
Chris Sinclair
  • 22,858
  • 3
  • 52
  • 93
  • Ah, I feared this solution. I have no way on raising the event, as the class that contains it doesn´t provide any methods to the outside, just the events. However that´s out of the scope of that question. – MakePeaceGreatAgain Feb 09 '18 at 15:41
  • @HimBromBeere: ¯\\_(ツ)_/¯ Such is the life of testing non-testable classes. Yeah, good chance you'll need to look at using a subclass (assuming the invocation is limited to subclasses), or `[InternalsVisibleTo]` to expose an `internal` invocation method, or reflection, or simply changing/improving the design so that the API is testable. – Chris Sinclair Feb 09 '18 at 16:15