Question

I need to do something that seems quite simple, but I cant seem to achieve it.

I need to be able to write a unit test that calls the action and filter delegates of any subscription to an eventaggregator event.

For example, in my class that needs to be tested I have the following code:

this.eventAggregator.GetEvent<RiskDataViewsJournalChangedEvent>().Subscribe(
    this.OnViewRequestPublished, ThreadOption.UIThread, false, this.EventFilter);

and I want my test to call the this.OnViewRequestPublished method and this.EventFilter method.

Ive tried using an instance of the EventAggregator class in my test but the events never get fired without a dispatcher present, which is not helpfull in a unit test.

Therefore I want to use Rhino Mocks, but I cant get my head around how to achieve what I need.

Thanks

Dean

Was it helpful?

Solution

Ive solved it myself - here is my code (ignore the EventToken references, this is something ive created myself for event filtering).

[Test]
public void RiskDataGridViewModelEventSubscriptionTests()
{
    // event token
    var tok = new EventToken();

    // mock event aggregator
    var agg = MockRepository.GenerateStub<IEventAggregator>();

    // my target class subscribes to 3 events in its constructor
    var evt1 = MockRepository.GenerateStub<RiskDataViewsJournalChangedEvent>();
    var evt2 = MockRepository.GenerateStub<RiskDataViewsJournalChangingEvent>();
    var evt3 = MockRepository.GenerateStub<RiskDataViewRequestPublishEvent>();

    // ensure mocked event classes are returned
    agg.Stub(x => x.GetEvent<RiskDataViewsJournalChangedEvent>()).Return(evt1);
    agg.Stub(x => x.GetEvent<RiskDataViewsJournalChangingEvent>()).Return(evt2);
    agg.Stub(x => x.GetEvent<RiskDataViewRequestPublishEvent>()).Return(evt3);

    // instantiate target class - in my class the events get subscribed to in the constructor
    new RiskDataGridViewModel(agg, tok, null);

    // get the parameters passed to the subscribe method
    var args1 = evt1.GetArgumentsForCallsMadeOn(s => s.Subscribe(null));
    var args2 = evt2.GetArgumentsForCallsMadeOn(s => s.Subscribe(null));
    var args3 = evt3.GetArgumentsForCallsMadeOn(s => s.Subscribe(null));

    // invoke filters
    ((Predicate<EventParameter<IRiskDataViewResultItem>>)args1[0][3]).Invoke(new EventParameter<IRiskDataViewResultItem>(null, tok));
    ((Predicate<EventParameter>)args2[0][3]).Invoke(new EventParameter(null, tok));
    ((Predicate<EventParameter<ViewRequest>>)args3[0][3]).Invoke(new EventParameter<ViewRequest>(null, tok));

    // invoke methods
    ((Action<EventParameter<IRiskDataViewResultItem>>)args1[0][0]).Invoke(new EventParameter<IRiskDataViewResultItem>(null, tok));
    ((Action<EventParameter>)args2[0][0]).Invoke(new EventParameter(null, tok));
    ((Action<EventParameter<ViewRequest>>)args3[0][0]).Invoke(new EventParameter<ViewRequest>(null, tok));

}

OTHER TIPS

/// <remarks>Event.Publish does not work in unit tests when subscribed with ThreadOption.UIThread </remarks>
public void FireGlobalEvent<TEvent, TEventArgs>(TEventArgs args)
    where TEvent : CompositePresentationEvent<TEventArgs>, new ()
{
    var globalEvent = GetInstance<IEventAggregator>().GetEvent<TEvent>();
    var subscriptions = (IEnumerable)globalEvent.GetType().GetProperty("Subscriptions", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(globalEvent);
    foreach (DispatcherEventSubscription<TEventArgs> subscription in subscriptions.Cast<object>().ToArray())
    {
        subscription.Action.Invoke(args);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top