如何对返回ArgumentException的MediatR方法进行单元测试
问题根因
你遇到的报错是两个错误叠加导致的:
- 你写的回调是同步委托,
userDefinitionRepository.Create(user)抛出的ArgumentException会直接在同步执行阶段抛出,被Moq识别为Mock构造过程的异常,不会作为IMediator.Send方法返回的Task的异常透出 t as Task<Unit>的转换写法存在缺陷:只要Create方法的返回值不是Task<Unit>类型,as转换会直接返回null,后续await这个返回值时就会触发空引用异常,完全覆盖了你预期的ArgumentException。
正确实现方案
方案1:需要在Send回调中执行Create逻辑
把回调改为异步委托,不需要手动做Task类型转换,异常会自动封装到返回的Task中:
_mediatorMock.Setup(m => m.Send(It.IsAny<UpdateUserCommand>(), It.IsAny<CancellationToken>())) .Returns(async (UpdateUserCommand command, CancellationToken cancel) => { // 此处抛出的ArgumentException会被自动封装到Task<Unit>中 userDefinitionRepository.Create(user); return Unit.Value; });
方案2:仅模拟Send抛出预期异常(不需要实际调用Create)
直接用Moq提供的ThrowsAsync方法更简洁:
_mediatorMock.Setup(m => m.Send(It.IsAny<UpdateUserCommand>(), It.IsAny<CancellationToken>())) .ThrowsAsync(new ArgumentException("你的预期异常信息"));
异常验证写法
调用控制器方法时,用测试框架的异常断言校验即可,以xUnit为例:
// 校验调用Post方法时确实抛出了ArgumentException var exception = await Assert.ThrowsAsync<ArgumentException>(() => controller.Post(2, cmd)); // 可选:校验异常的参数名、消息等是否符合预期 Assert.Equal("你预期报错的参数名", exception.ParamName);
内容的提问来源于stack exchange,提问作者this-Me
相关产品推荐
相关产品推荐

