3

I am using Test Driven Development to develop a simple application using Xamarin Studio on Mac OS X. I'm using NUnit as the test harness and FakeItEasy for mocking. I've developed an object that fires an event, and I want to test that another object response to that event, however it seems that responding object never receives any events that are fires in the test.

The following code illustrates the problem:

using System;
using NUnit.Framework;
using FakeItEasy;

namespace EventTest
{
    public class EventProvider
    {
        public delegate void EventDelegate(object sender, EventArgs arguments);

        public EventDelegate Event;
    }

    class EventResponder
    {
        public EventResponder(EventProvider provider)
        {
            provider.Event += (sender, arguments) => ++EventCount;
        }

        public uint EventCount { get; private set; }
    }

    [TestFixture]
    public class EventResponderTest
    {
        [Test]
        public void ResponseToFiredEvent()
        {
            var eventProvider = A.Fake<EventProvider>();

            EventResponder responder = new EventResponder(eventProvider);

            eventProvider.Event += Raise.WithEmpty().Now;
            eventProvider.Event += Raise.WithEmpty().Now;
            eventProvider.Event += Raise.WithEmpty().Now;

            Assert.AreEqual(3, responder.EventCount);
        }
    }
}

The test fails because EventCount is 0. What does it take to make this test pass?

k.m
  • 30,794
  • 10
  • 62
  • 86
Tron Thomas
  • 871
  • 7
  • 20

1 Answers1

2

Your test doesn't work because FakeItEasy requires faked members to be virtual, or more generally — overridable, and the same holds for events that FakeItEasy raises. Your current event is not overridable. To fix it, either:

  • change Event member to virtual (public virtual event EventDelegate Event;)
  • hide EventProvider implementation behind interface, fake the interface instead of the class, and make your consumer (EventResponder) depend on the interface instead
Blair Conrad
  • 233,004
  • 25
  • 132
  • 111
k.m
  • 30,794
  • 10
  • 62
  • 86
  • @BlairConrad: It would be really nice if frameworks **did** warn/throw upon encountering such situation (attempt to mock something unmockable due to DynamicProxy limitations). IME, sheer volume of questions I've answered relating to this problem somehow proves it is not obvious topic to beginners. – k.m Sep 05 '14 at 10:19
  • In many cases (as many as we're able), FakeItEasy _does_ throw when we try to mock something that's not mockable. Try running `A.CallTo` on a non-virtual method. There's a nice error. I'm sure some spots are missed, but when we hear of such a thing, we try to add the explicit error. Here, I don't see how it's possible - there's no fake object at all. `Raise` has no fake to work with, and `EventResponder` is not faked in the test. If you think differently, and have time and inclination to investigate, @jimmy_keen, please find a way; I would welcome a chance to improve the behaviour here. – Blair Conrad Sep 05 '14 at 10:24
  • I'm not sure how I can make the Event member virtual. When I try changing it to: public virtual EventDelegate Event; I get this error when compiling: The modifier 'virtual' is not valid for this item. If I try something like: public EventDelegate virtual Event; I get this compiler error: Unexpected sybmol ';' in class, struct, or interface member declaration – Tron Thomas Sep 06 '14 at 17:02
  • 1
    Looks like I figured it out; I had to include the event keyword. i.e.: public virtual event EventDelegate Event; – Tron Thomas Sep 06 '14 at 17:19