Reputation: 4287
Before you begin reading please note that I've included all of the code for a complete example so it might be long. :D
I'm currently working on a project using Exchange Web Services (EWS) that is responsible for subscribing to EWS requesting callbacks to specific events whenever new mail arrives in specified mailboxes. However, we've been having issues with our email server for the few weeks. Since our implementation was so tightly coupled to Exchange being online we were not being able to continue work. This is when I had an idea of creating a small event handler implementation that could work with or without Exchange. Obviously, without Exchange being online I would have to manually raise events.
My reasoning for creating a generic event handler interface is that I could create an event handler class that could work with or without Exchange. So for an Exchange implementation I'd have IEventHander<>
. And for a dummy implementation I'd have EventHandlerBase<NotificationEventArgs, DisconnectEventArgs, ErrorEventArgs>
, which is what I've shown below. Also, all EventArgs objects from the latter are custom with no functionality whatsoever.
See below what I have thus far.
public interface IEventHandler
<TOnNotification, TOnDisconnect, TOnSubscriptionError>
where TOnNotification : EventArgs
where TOnDisconnect : EventArgs
where TOnSubscriptionError : EventArgs
{
event EventHandler<TOnNotification> OnNotification;
event EventHandler<TOnDisconnect> OnDisconnect;
event EventHandler<TOnSubscriptionError> OnSubscriptionError;
void OnNotificationEvent(object sender, TOnNotification args);
void OnDisconnectEvent(object sender, TOnDisconnect args);
void OnErrorEvent(object sender, TOnSubscriptionError args);
}
public abstract class EventHandlerBase<TOnNotification, TOnDisconnect, TOnError>
: IEventHandler<TOnNotification, TOnDisconnect, TOnError>
where TOnNotification : EventArgs
where TOnDisconnect : EventArgs
where TOnError : EventArgs
{
public event EventHandler<TOnNotification> OnNotification;
public event EventHandler<TOnDisconnect> OnDisconnect;
public event EventHandler<TOnError> OnSubscriptionError;
public abstract void OnNotificationEvent(object sender, TOnNotification args);
public abstract void OnDisconnectEvent(object sender, TOnDisconnect args);
public abstract void OnErrorEvent(object sender, TOnError args);
}
public class DummyEventHandler :
EventHandlerBase<NotificationEventArgs, DisconnectEventArgs, ErrorEventArgs>
{
public override void OnNotificationEvent(object sender, NotificationEventArgs args)
{
Console.WriteLine(MethodBase.GetCurrentMethod());
}
public override void OnDisconnectEvent(object sender, DisconnectEventArgs args)
{
Console.WriteLine(MethodBase.GetCurrentMethod());
}
public override void OnErrorEvent(object sender, ErrorEventArgs args)
{
Console.WriteLine(MethodBase.GetCurrentMethod());
}
}
public interface ISubscriber
{
void Subscribe();
void Unsubcribe();
}
public class DummyStreamingNotificationSubscriber : ISubscriber
{
private readonly IEventHandler<NotificationEventArgs, DisconnectEventArgs, ErrorEventArgs> _eventHandler;
public DummyStreamingNotificationSubscriber(
IEventHandler<NotificationEventArgs, DisconnectEventArgs, ErrorEventArgs> eventHandler)
{
_eventHandler = eventHandler;
}
public void Subscribe()
{
Console.WriteLine("Subscribing to streaming notification.");
var streamingConnection = new DummyStreamingSubscriptionConnection();
streamingConnection.OnNotification += _eventHandler.OnNotificationEvent;
streamingConnection.OnDisconnect += _eventHandler.OnDisconnectEvent;
streamingConnection.OnError += _eventHandler.OnErrorEvent;
}
public void Unsubcribe()
{
Console.WriteLine("Unsubscribing to streaming notification.");
}
}
// Only used to mimic EWS' StreamingSubscriptionConnection class
public class DummyStreamingSubscriptionConnection
{
public event EventHandler<NotificationEventArgs> OnNotification;
public event EventHandler<DisconnectEventArgs> OnDisconnect;
public event EventHandler<ErrorEventArgs> OnError;
}
// Mimics EWS' NotificationEventArgs class
public class NotificationEventArgs : EventArgs { }
// Mimics EWS' SubscriptionErrorEventArgs class
public class ErrorEventArgs : EventArgs { }
// Mimics EWS' SubscriptionErrorEventArgs class
public class DisconnectEventArgs : EventArgs { }
public class DummyService : IService
{
private readonly ISubscriber _subscriber;
public DummyService(ISubscriber subscriber)
{
_subscriber = subscriber;
}
public void Start()
{
Console.WriteLine("Starting service.");
_subscriber.Subscribe();
}
public void Stop()
{
Console.WriteLine("Stopping service.");
_subscriber.Unsubcribe();
}
}
And finally, glue it all together.
var service = new DummyService(
new DummyStreamingNotificationSubscriber(
new DummyEventHandler()));
service.Start();
In the ExchangeEventHandler
class is where OnNotificationEvent()
would fetch the email and work with it. In short, I need to be able stub out (e.g. with DI) the event handling to ensure I can still work with my streaming subscription service with or without Exchange.
How can I test that raising an OnNotification
event will actually call the appropriate method and do what it's supposed to do (e.g. consume the email). I'm assuming mocking will come in play. Essentially, I want to ensure that once the real service implementation is in play that once for example event OnNotification
fires it'll actually keep on running its course.
Please don't hesitate to ask question if something isn't clear. I do realize this might not be the perfect solution therefore I'm also open to different implementation suggestions.
Upvotes: 1
Views: 938
Reputation: 3777
To check whether approp method gets called after raising event or any other function call, you will need to use StrictMock and Mock raising that event (I use RhynoMocks).
you might want to separate out/ break down what functionality you want to test in your execution code.
If you want to test functionality around "making sure that Event calls particular X method" (and just to test it does call that X method), in your DummyEventHandler
example, you want to make sure Console.WriteLine(MethodBase.GetCurrentMethod())
gets called right?
You can use RhynoMocks to do that:
var mocks = new MockRepository();
IEventHandler eventHandler = MockRepository.GenerateStrictMock<IEventHandler>()
eventHandler.Expect( x => x.OnNotificationEvent(null, null).IgnoreArguments();
(do above for other methods)
and then:
var service = new DummyService(
new DummyStreamingNotificationSubscriber(eventHandler));
service.Start();
Make sure when you service starts, make sure your DummyStreamingSubscriptionConnection
publishes/invokes the events
Upvotes: 3