单元测试控制器时MediatR返回Null问题求助
MediatR Mock返回Null的问题解决方法
你的问题出在Moq的参数匹配逻辑上:
在测试代码里,你给MediatR的Send方法Setup时用的是自己创建的query实例:
_mediator.Setup(x => x.Send(query, It.IsAny<CancellationToken>())).ReturnsAsync(mappedAuthor);
但控制器内部会新建一个完全独立的GetAuthorQuery对象:
var query = new GetAuthorQuery(authorId);
Moq默认对引用类型参数采用引用相等匹配,这两个实例不是同一个对象,所以Mock的Setup不会被触发,Send方法自然返回默认的Null。
解决办法(推荐第一种)
1. 使用参数条件匹配
把Setup里的query替换成按属性值匹配的条件,只要Query的AuthorId和测试用的ID一致就触发:
// 替换原来的MediatR Setup代码 _mediator.Setup(x => x.Send( It.Is<GetAuthorQuery>(q => q.AuthorId == author.Id), It.IsAny<CancellationToken>() )).ReturnsAsync(mappedAuthor);
2. 给GetAuthorQuery实现值相等
如果你的Query对象需要经常按值匹配,可以重写它的Equals和GetHashCode方法:
public class GetAuthorQuery : IRequest<AuthorDto> { public int AuthorId { get; } public GetAuthorQuery(int authorId) { AuthorId = authorId; } public override bool Equals(object obj) { return obj is GetAuthorQuery query && AuthorId == query.AuthorId; } public override int GetHashCode() { return HashCode.Combine(AuthorId); } }
这样Moq就能正确识别两个属性相同的Query实例是相等的,原来的Setup代码就可以正常工作。
额外优化
你的测试代码里有一行多余的Setup:
_authorRepository.Setup(r=>r.GetAuthor(author.Id)).ReturnsAsync(author);
控制器里根本没有直接依赖IAuthorRepository,而是通过MediatR发送Query,所以这个Setup完全没用,可以删掉,避免混淆。
修改后的完整测试方法:
[Test] public async Task GetAuthor_Returns_Ok() { var author = fixture.Build<Author>().Create(); var mappedAuthor= _mapper.Map<AuthorDto>(author); var controller = new AuthorController(_mediator.Object); // 用条件匹配设置MediatR _mediator.Setup(x => x.Send( It.Is<GetAuthorQuery>(q => q.AuthorId == author.Id), It.IsAny<CancellationToken>() )).ReturnsAsync(mappedAuthor); var result = await controller.GetAuthor(author.Id); var obj = result as ObjectResult; Assert.AreEqual(200, obj.StatusCode); }
内容的提问来源于stack exchange,提问作者Sev
相关产品推荐
相关产品推荐

