单元测试中使用Moq模拟服务时触发空引用异常的问题求助
单元测试中使用Moq模拟服务时触发空引用异常的问题求助
嗨,我来帮你排查这个问题~
从你描述的情况和代码来看,空引用异常的根源是Moq的方法匹配没有命中,导致_service.CreateTransactionAsync(payload)返回了默认的null,后续访问res.Status自然就抛出异常了。
问题具体原因
你在Mock设置阶段用的是TransactionFixture.CreateTransaction()创建的一个请求实例,但在调用控制器方法时,又重新调用了一次TransactionFixture.CreateTransaction()生成了另一个新的实例。Moq默认采用引用相等匹配,这两个实例是不同的对象,所以Mock不会返回你预设的transactionResponse,最终res变量为null。
修复方案(三种可选)
方案1:匹配任意类型的参数(最简便)
如果你不需要精确匹配请求参数的内容,只需要确保Mock的方法被触发,可以用It.IsAny<T>()来匹配任意TransactionReqDto类型的参数:
// Arrange部分修改Setup代码 mockTransactionService.Setup(service => service.CreateTransactionAsync(It.IsAny<TransactionReqDto>())) .ReturnsAsync(transactionResponse);
方案2:精确匹配参数的属性值
如果需要验证请求参数的具体属性是否符合预期,可以用It.Is<T>()结合断言来匹配:
var expectedRequest = TransactionFixture.CreateTransaction(); mockTransactionService.Setup(service => service.CreateTransactionAsync(It.Is<TransactionReqDto>(req => req.Id == expectedRequest.Id && req.Amount == expectedRequest.Amount // 替换成你需要校验的实际属性 ))) .ReturnsAsync(transactionResponse);
方案3:使用同一个请求实例
确保Setup和Act阶段使用的是同一个TransactionReqDto实例,这样引用匹配就能命中:
// Arrange var transactionRequest = TransactionFixture.CreateTransaction(); // 只创建一次实例 var transactionResponse = new TransactionResDto { Status = true }; mockTransactionService.Setup(service => service.CreateTransactionAsync(transactionRequest)) .ReturnsAsync(transactionResponse); var mockTransactionController = new TransactionController(mockTransactionService.Object); // Act var result = (OkObjectResult) await mockTransactionController.CreateTransaction(transactionRequest); // 复用同一个实例
额外建议
为了确保测试的严谨性,你可以在断言阶段加上对Mock方法调用的验证,确认服务方法确实被调用了:
// Assert部分新增 mockTransactionService.Verify(service => service.CreateTransactionAsync(It.IsAny<TransactionReqDto>()), Times.Once);
备注:内容来源于stack exchange,提问作者Seyi Agboola
相关产品推荐
相关产品推荐

