【发布时间】:2017-09-01 04:01:09
【问题描述】:
我们最近开始使用 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
}
}
}
测试
public class TransferHandlerTests
{
[Theory]
[AutoData]
public async void HandlerCreatesTransfer(Mock<IMediator> mockMediator)
{
// Note that default(CancellationToken) is the default value of the optional argument.
mockMediator.Setup(m => m.Send(It.IsAny<TransferNotificationCommand>(), default(CancellationToken))).Verifiable("Notification was not sent.");
var handler = new TransferHandler(mockMediator.Object);
var actual = await handler.Handle(message);
mockMediator.Verify(x => x.Send(It.IsAny<CreateIsaTransferNotificationCommand>(), default(CancellationToken)), Times.Once());
}
}
我错过了什么?我觉得我在某个地方犯了一个根本性的错误,但我不确定在哪里。
【问题讨论】:
-
Test sn-p中的那个参数应该叫
mediator吗? -
@OutstandingBill 不,这是一个没有人发现的错字!我已经编辑过了
标签: c# unit-testing moq xunit mediatr