XUnit测试AddComment接口时BugViewModel的Comments属性为null如何解决
问题根因
- 你当前编写的是控制器层单元测试,测试代码中使用NSubstitute mock了
IBugService依赖,测试执行时不会运行你编写的真实BugService.AddComment业务逻辑,AddComment的返回值完全由你手动指定。 - 你给mock的
AddComment方法配置的返回值是new Option<BugViewModel>.Some(new BugViewModel()),直接new生成的BugViewModel没有给Comments属性赋值,默认值为null,所以后续执行Assert.Single时会抛出空引用异常。 - 补充说明:当前的测试定位不清晰,控制器层单元测试只需验证控制器对服务返回结果的转发逻辑是否正确,「添加评论后ViewModel包含对应评论」属于业务逻辑校验,应该放在BugService层的单元测试中实现。
修复方案
根据你的测试目标,可选择以下两种方案:
方案1:保留控制器单元测试,验证控制器转发逻辑正确
控制器的核心逻辑是:服务返回Some则包装为200响应返回、返回None则返回404。只需构造符合预期的返回值传给mock服务即可:
[Fact] public async Task AddComment_WhenServiceReturnSome_ReturnsOkWithComment() { // 构造预期返回的带评论的BugViewModel var expectedBug = new BugViewModel { Id = Guid.NewGuid(), Comments = new List<BugCommentViewModel> { new BugCommentViewModel { Text = "测试评论", Commenter = "测试用户", CommentedAt = DateTime.Now } } }; // 配置mock服务返回上述构造的实例 _fixture.BugService.AddComment(Arg.Any<Guid>(), Arg.Any<AddCommentForm>()) .Returns(new Option<BugViewModel>.Some(expectedBug)); var sut = _fixture.GetSut(); var result = await sut.AddComment(Guid.NewGuid(), new AddCommentForm()); // 校验返回结果符合预期 var okResult = Assert.IsType<OkObjectResult>(result); var actualBug = Assert.IsType<BugViewModel>(okResult.Value); Assert.Same(expectedBug, actualBug); Assert.Single(actualBug.Comments); }
方案2:编写BugService层单元测试,验证真实业务逻辑
如果你的测试目标是校验「添加评论后确实会生成带评论的ViewModel」,就需要构造真实的BugService实例,只mock它依赖的DbContext(或使用内存数据库),示例逻辑如下:
- 初始化支持单元测试的DbContext实例(推荐使用EF Core的内存数据库)
- 提前写入一条测试用的Bug数据到数据库
- 构造真实的
BugService实例,注入上述DbContext - 调用
AddComment方法传入评论参数 - 校验返回的
BugViewModel的Comments集合长度为1,且内容和传入参数一致
额外注意:如果测试Service时遇到Bug.Comments为null的问题,需要在查询Bug时加上Include(x => x.Comments)加载导航属性,或者给Bug实体类的Comments属性添加默认初始化:public List<BugComment> Comments { get; set; } = new List<BugComment>();
内容的提问来源于stack exchange,提问作者Tania Marinova
相关产品推荐
相关产品推荐

