使用Caliburn事件聚合器为包含PublishOnUIThreadAsync的方法设置moq

时间:2017-09-06 03:45:26

标签: .net unit-testing asynchronous moq caliburn.micro

从我的previous question,我了解到我必须Mock.SetupeventAggregatorMoq知道返回数据。

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

以下内容适用于覆盖上述包装方法,该方法不是await并返回void

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

那么,如果我正在等待返回Task的方法,我该怎么设置呢。

public async Task Navigate() {
    await eventAggregator.PublishOnUIThreadAsync(new MyEvent(5));
}

1 个答案:

答案 0 :(得分:0)

基于PublishOnUIThreadAsync扩展方法,返回任务

/// <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;
}

您会注意到任务是在Publish正在执行的操作中分配的。您需要调用该操作,以便通过确保调用委托/操作来分配任务。你可以在模拟方法的回调中做到这一点。

以下最小示例演示了如何执行此操作。注意如何设置Publish以回调调用传入的Action参数。

[TestClass]
public class MyTestClass {

    [TestMethod]
    public async Task _EventAggregator_Should_Publish_OnUIThread() {
        //Arrange
        MyEvent navigateEvent = null;
        var eventAggregatorMock = new Mock<IEventAggregator>();
        eventAggregatorMock
            .Setup(x => x.Publish(It.IsAny<MyEvent>(), It.IsAny<Action<System.Action>>()))
            .Callback((object message, Action<System.Action> marshal) => {
                navigateEvent = (MyEvent)message;
                marshal(() => { });//Invoking action that would cause task to be assigned
            });
        var sut = new MyClass(eventAggregatorMock.Object);
        //Act
        await sut.Navigate();
        //Assert
        navigateEvent.Should().NotBeNull();
        eventAggregatorMock.Verify(_ => _.Publish(It.IsAny<MyEvent>(), 
            It.IsAny<Action<System.Action>>()), Times.Once);
    }

    public class MyEvent {
        private int p;

        public MyEvent(int p) {
            // TODO: Complete member initialization
            this.p = p;
        }

    }
    public class MyClass {
        IEventAggregator eventAggregator;
        public MyClass(IEventAggregator eventAggregator) {
            this.eventAggregator = eventAggregator;
        }

        public async Task Navigate() {
            await eventAggregator.PublishOnUIThreadAsync(new MyEvent(5));
        }
    }
}