Moq验证INotificationHubClient调用提示This setup was not matched报错如何解决
问题根本原因
- 你当前的匹配规则用
==直接比较引用类型实例:AndroidNotification和string[]都是引用类型,默认==执行引用相等性校验,被测代码中创建的AndroidPayload、tags和测试代码中定义的对比对象是不同的堆实例,引用地址不一致,因此匹配失败。 - 使用
It.IsAny时跳过了参数校验,因此可以通过测试,但无法验证参数正确性。
解决方案
你可以通过以下几种方式修改参数匹配规则,实现参数值校验:
方案1:自定义属性匹配规则
直接校验对象内部的属性值,代替引用比较:
// 首先在测试代码中定义好预期值 var expectedPayload = new SomeDataType { /* 填充预期属性 */ }; var expectedTags = new string[] { "userName1", "userName2" }; _hubClient .Setup(s => s.SendFcmNativeNotificationAsync( // 校验AndroidNotification内部的Data属性是否符合预期 It.Is<AndroidNotification>(a => a.Data.Property1 == expectedPayload.Property1 && a.Data.Property2 == expectedPayload.Property2), // 校验数组元素是否完全一致,需要引入System.Linq命名空间 It.Is<string[]>(s => s.SequenceEqual(expectedTags)) )) .ReturnsAsync(retVal) .Verifiable();
如果SomeDataType已经重写了Equals方法,也可以简化为a.Data.Equals(expectedPayload)。
方案2:使用Moq内置深比较(推荐,Moq 4.16+版本支持)
Moq提供了It.DeepEquals方法,可以自动递归比较两个对象的所有公有属性值,无需手动编写属性校验逻辑:
var expectedAndroidPayload = new AndroidNotification { Data = expectedPayload }; var expectedTags = new string[] { "userName1", "userName2" }; _hubClient .Setup(s => s.SendFcmNativeNotificationAsync( It.Is<AndroidNotification>(a => It.DeepEquals(a, expectedAndroidPayload)), It.Is<string[]>(s => It.DeepEquals(s, expectedTags)) )) .ReturnsAsync(retVal) .Verifiable();
方案3:捕获调用参数后单独校验
如果参数校验逻辑复杂,或者需要更清晰的错误提示,可以先配置任意参数匹配,执行被测方法后再单独断言参数:
// 先配置任意参数的调用返回值 _hubClient .Setup(s => s.SendFcmNativeNotificationAsync(It.IsAny<AndroidNotification>(), It.IsAny<string[]>())) .ReturnsAsync(retVal); // 执行被测方法 await _notificationService.SendNotificationAsync(payloadData); // 校验调用的参数和次数 _hubClient.Verify(s => s.SendFcmNativeNotificationAsync( It.Is<AndroidNotification>(a => It.DeepEquals(a.Data, expectedPayload)), It.Is<string[]>(s => s.SequenceEqual(expectedTags)) ), Times.Once, "调用参数不符合预期");
该方案在参数不匹配时会抛出明确的断言错误,方便定位问题。
内容的提问来源于stack exchange,提问作者Stephanos B.
相关产品推荐
相关产品推荐

