Xunit使用Moq验证方法调用失败 方法实际已被调用
问题场景
使用Moq 4.18.1对C#代码做单元测试,需要验证调用GetAsync方法时,内部受保护的虚方法IpSpecificGetterExtras会被执行。
被测类代码如下:
public class IntegratedPlatformRepository : PvRepository<OutputDTO>, IIntegratedPlatformRepository { protected virtual async Task IpSpecificGetterExtras(OutputDTO dto, CancellationToken cancellationToken) { } public async Task<OutputDTO> GetAsync(Guid uid, CancellationToken cancellationToken = default) { var dto = ... await IpSpecificGetterExtras(dto, cancellationToken); ... } }
初始编写的测试代码如下:
[Fact] public async Task GetAsync_Calls_IpSpecificGetterExtras() { // Arrange var mock = new Mock<IntegratedPlatformRepository> { CallBase = true }; // Act await _repo.GetAsync(Guid.NewGuid().ToString()); // Assert mock .Protected() .Verify<Task>( "IpSpecificGetterExtras", Times.Once(), ItExpr.IsAny<OutputDTO>(), ItExpr.IsAny<CancellationToken>() ); }
运行测试时出现异常:直接执行测试用例失败,提示未检测到IpSpecificGetterExtras的调用;但调试测试时,IpSpecificGetterExtras方法内的断点可以正常命中,方法确实被执行。
失败原因
核心问题有两个:
- 调用实例不匹配:你在Arrange阶段创建了
IntegratedPlatformRepository的Mock代理对象,但Act阶段调用的是测试类中独立存在的_repo实例的GetAsync方法,这个_repo和你创建的mock对象没有任何关联,mock代理根本没有拦截到任何方法调用,内部的调用记录为空,自然Verify校验失败。调试时断点能命中,是因为_repo本身是真实的仓储实例,执行自身逻辑时当然会进入IpSpecificGetterExtras,但这个过程完全不在mock的监控范围内。 - 参数类型不匹配:被测方法
GetAsync的第一个参数是Guid类型,测试代码中传入的是Guid.NewGuid().ToString()生成的字符串,会导致编译错误或者调用到错误的方法重载,进一步导致mock无法匹配到预期的调用逻辑。
修复方案
- 首先确保Act阶段调用的是Mock生成的代理实例(即
mock.Object)的GetAsync方法,如果IntegratedPlatformRepository构造函数需要依赖参数,在创建Mock实例时传入对应参数。 - 修正传入
GetAsync的参数类型,传入合法的Guid值而非字符串。
修正后的测试代码:
[Fact] public async Task GetAsync_Calls_IpSpecificGetterExtras() { // Arrange // 构造函数有依赖的话,在Mock构造函数中传入对应参数 var mock = new Mock<IntegratedPlatformRepository>() { CallBase = true // 配置为执行真实的基类逻辑 }; var testUid = Guid.NewGuid(); // Act // 必须调用mock生成的代理实例的方法,才能让mock拦截到内部调用 await mock.Object.GetAsync(testUid); // Assert mock .Protected() .Verify<Task>( "IpSpecificGetterExtras", Times.Once(), ItExpr.IsAny<OutputDTO>(), ItExpr.IsAny<CancellationToken>() ); }
补充说明:Moq验证受保护方法时必须使用
ItExpr而非普通的It做参数匹配,原测试代码中这部分写法是正确的,不需要修改。
内容的提问来源于stack exchange,提问作者Gargoyle
相关产品推荐
相关产品推荐

