3

I have an event as following

namespace MyProject
{
    public class MyEvent
    {
        public MyEvent(int favoriteNumber)
        {
            this.FavoriteNumber = favoriteNumber;
        }

        public int FavoriteNumber { get; private set; }
    }
}

And I have a method which raises this event.

using Caliburn.Micro;
//please assume the rest like initializing etc.
namespace MyProject
{
    private IEventAggregator eventAggregator;

    public void Navigate()
    {
        eventAggregator.PublishOnUIThreadAsync(new MyEvent(5));
    }
}

If I using just PublishOnUIThread, the below code (in an unit test) is working fine.

eventAggregatorMock.Verify(item => item.Publish(It.IsAny<MyEvent>(), Execute.OnUIThread), Times.Once);

But how do I check for async version for the same?

eventAggregatorMock.Verify(item => item.Publish(It.IsAny<MyEvent>(), Execute.OnUIThreadAsync), Times.Once);

Facing trouble verifying the async method. Assume private Mock<IEventAggregator> eventAggregatorMock;. The part Execute.OnUIThreadAsync gives error 'Task Execute.OnUIThreadAsync' has the wrong return type.

I also tried

eventAggregatorMock.Verify(item => item.Publish(It.IsAny<MyEvent>(), action => Execute.OnUIThreadAsync(action)), Times.Once);

But says, System.NotSupportedException: Unsupported expression: action => action.OnUIThreadAsync()

Thanks in advance.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
Hussain Mir
  • 107
  • 7

1 Answers1

0

IEvenAggregator.Publish is defined as

void Publish(object message, Action<System.Action> marshal);

Therefore you would need to provide a proper expression to match that definition.

eventAggregatorMock.Verify(_ => _.Publish(It.IsAny<MyEvent>(), 
                                It.IsAny<Action<System.Action>>()), Times.Once);

Also PublishOnUIThreadAsync extension method returns a Task

/// <summary>
/// Publishes a message on the UI thread asynchrone.
/// </summary>
/// <param name="eventAggregator">The event aggregator.</param>
/// <param name="message">The message instance.</param>
public static Task PublishOnUIThreadAsync(this IEventAggregator eventAggregator, object message) {
    Task task = null;
    eventAggregator.Publish(message, action => task = action.OnUIThreadAsync());
    return task;
}

so it should be awaited

public async Task Navigate() {
    await eventAggregator.PublishOnUIThreadAsync(new MyEvent(5));
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • FYI, it worked without modifying the method as you prescribed. If I tried to `await` it, I get `System.NullReferenceException: Object reference not set to an instance of an object.` – Hussain Mir Aug 30 '17 at 16:46
  • @HussainMir that is because there was no setup that would return a task so it was null. https://github.com/Caliburn-Micro/Caliburn.Micro/blob/master/src/Caliburn.Micro/Execute.cs#L30 – Nkosi Aug 30 '17 at 16:47
  • Hi, I've tried this `MyEvent navigateEvent = null; eventAggregatorMock.Setup(x => x.Publish(It.IsAny(), It.IsAny>())).Callback>((t, s) => navigateEvent = (MyEvent)t);` But still the test was failing. Any hint on how to setup? – Hussain Mir Aug 30 '17 at 20:02
  • @HussainMir you were almost there. You did not invoke the action that would have cause the Task to be assigned to allow for the async flow. Provided it in the new related question. – Nkosi Sep 06 '17 at 13:15