Ste*_*fer 10 c# unit-testing moq xunit mediatr
我们最近开始使用MediatR来允许我们解除控制器操作的混乱,因为我们重新考虑面向客户的大型门户并将其全部转换为C#.作为其中的一部分,我们也在增加我们的单元测试覆盖率,但是在尝试模拟MediatR本身时遇到了问题.
该命令执行一系列操作以启动进程,其中一部分是发送通知.通知本身由其自己的处理程序处理,因此将受其自己的单元测试的影响,因此我想模拟MediatR,以便this.mediator.Send(message)调用不会真正做任何事情.处理程序确实返回一个对象,但我们在这个上下文中并不关心它,因此对于所有意图和目的,我们将它视为一个void返回.我只想验证Send作为测试的一部分已被调用过一次.但是,Send方法是抛出一个NullReferenceException,我不知道为什么.
截至3版本,MediatR现在呈现出第二个可选参数Send,一个CancellationToken和表达式树需要你明确地设置他们,你必须指定一个值.我之前没有遇到过这种情况,在我看来,我觉得这可能是问题的一部分,但这可能是我的混淆.
这是一个减少的插图.
SUT
public class TransferHandler : IAsyncRequestHandler<TransferCommand, TransferResult>
{
private readonly IMediator mediator;
public TransferHandler(IMediator mediator)
{
this.mediator = mediator;
}
public async Task<TransferResult> Handle(TransferCommand message)
{
// Other stuff.
var notification = new TransferNotificationCommand()
{
ClientId = message.clientId,
OfficeId = message.OfficeId,
AuthorityFileId = letter?.Id
};
await this.mediator.Send(notification); // <=== This is where we get a NullReferenceException, even though nothing is actually null (that I can see).
return new TransferResult()
{
Transfer = transfer,
FileId = letter?.Id
}
}
}
Run Code Online (Sandbox Code Playgroud)
测试
public class TransferHandlerTests
{
[Theory]
[AutoData]
public async void HandlerCreatesTransfer(Mock<IMediator> mockMediator)
{
// Note that default(CancellationToken) is the default value of the optional argument.
mediator.Setup(m => m.Send(It.IsAny<TransferNotificationCommand>(), default(CancellationToken))).Verifiable("Notification was not sent.");
var handler = new TransferHandler(mediator.Object);
var actual = await handler.Handle(message);
mediator.Verify(x => x.Send(It.IsAny<CreateIsaTransferNotificationCommand>(), default(CancellationToken)), Times.Once());
}
}
Run Code Online (Sandbox Code Playgroud)
我错过了什么?我觉得我在某个地方犯了一个根本性的错误,但我不确定在哪里.
Nko*_*osi 15
您需要在Send返回任务时处理方法的异步操作等待.
/// <summary>
/// Asynchronously send a request to a single handler
/// </summary>
/// <typeparam name="TResponse">Response type</typeparam>
/// <param name="request">Request object</param>
/// <param name="cancellationToken">Optional cancellation token</param>
/// <returns>A task that represents the send operation. The task result contains the handler response</returns>
Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Asynchronously send a request to a single handler without expecting a response
/// </summary>
/// <param name="request">Request object</param>
/// <param name="cancellationToken">Optional cancellation token</param>
/// <returns>A task that represents the send operation.</returns>
Task Send(IRequest request, CancellationToken cancellationToken = default(CancellationToken));
Run Code Online (Sandbox Code Playgroud)
这意味着您需要让模拟返回一个任务,以允许异步进程继续流程
mediator
.Setup(m => m.Send(It.IsAny<TransferNotificationCommand>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new Notification()) //<-- return Task to allow await to continue
.Verifiable("Notification was not sent.");
//...other code removed for brevity
mediator.Verify(x => x.Send(It.IsAny<CreateIsaTransferNotificationCommand>(), It.IsAny<CancellationToken>()), Times.Once());
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5797 次 |
| 最近记录: |