如何优化验证无线设备方法调用情况的自定义函数?
优化方法调用验证函数的实现方案
我需要实现一个可接收方法名称,并验证该方法是否被调用的功能,目前已编写如下自定义函数,现寻求更优的实现方案。
更新说明:根据反馈已对该函数进行更新,欢迎提出进一步优化意见。
原实现代码:
private void Then_WirelessDeviceInvokedMethod( ushort unitId, string methodName = null, int expectedCallCount = 1, IReadOnlyList<object> expectedArgs = null) { if (expectedArgs == null) { expectedArgs = new List<object>(); } var wdm = GetWirelessDeviceMock(unitId); Assert.That(wdm, Is.Not.Null); uint callCount = 0; foreach (var invocation in wdm.Invocations) { if (invocation.Method.Name == methodName && invocation.Arguments.Count == expectedArgs.Count) { bool hasSameArgs = true; for (int i = 0; i < invocation.Arguments.Count; i++) { if (!invocation.Arguments[i].Equals(expectedArgs[i])) { hasSameArgs = false; break; } } if (hasSameArgs) { callCount++; } } } Assert.That(callCount, Is.EqualTo(expectedCallCount)); }
优化方向与实现
1. 利用Mock框架原生断言(假设使用Moq)
如果wdm是Moq的Mock<T>实例,直接用框架自带的Verify方法替代手动遍历,代码更简洁且失败提示更清晰:
private void Then_WirelessDeviceInvokedMethod( ushort unitId, string methodName = null, int expectedCallCount = 1, IReadOnlyList<object> expectedArgs = null) { expectedArgs ??= new List<object>(); var wdm = GetWirelessDeviceMock(unitId); Assert.That(wdm, Is.Not.Null); var mock = wdm as Mock<IWirelessDevice>; // 替换为你的实际接口类型 Assert.That(mock, Is.Not.Null, "获取到的Mock对象类型不匹配"); if (string.IsNullOrEmpty(methodName)) { mock.VerifyAll(); return; } // 查找目标方法 var method = typeof(IWirelessDevice).GetMethod(methodName, expectedArgs.Select(a => a.GetType()).ToArray()); Assert.That(method, Is.Not.Null, $"未找到名为{methodName}的方法"); // 构建方法调用表达式 var instanceParam = Expression.Parameter(typeof(IWirelessDevice), "x"); var callExpr = Expression.Call(instanceParam, method, expectedArgs.Select(arg => Expression.Constant(arg)).ToArray()); var actionExpr = Expression.Lambda<Action<IWirelessDevice>>(callExpr, instanceParam); mock.Verify(actionExpr, Times.Exactly(expectedCallCount)); }
2. 用LINQ简化手动计数逻辑
如果必须手动遍历Invocations,用LINQ替代嵌套循环,代码更紧凑:
private void Then_WirelessDeviceInvokedMethod( ushort unitId, string methodName = null, int expectedCallCount = 1, IReadOnlyList<object> expectedArgs = null) { expectedArgs ??= new List<object>(); var wdm = GetWirelessDeviceMock(unitId); Assert.That(wdm, Is.Not.Null); var callCount = wdm.Invocations.Count(invocation => invocation.Method.Name == methodName && invocation.Arguments.Count == expectedArgs.Count && invocation.Arguments.Zip(expectedArgs, (invArg, expArg) => invArg.Equals(expArg)).All(b => b)); Assert.That(callCount, Is.EqualTo(expectedCallCount), $"方法{methodName}调用次数不符合预期:预期{expectedCallCount}次,实际{callCount}次"); }
3. 增强类型安全(推荐)
避免用字符串硬编码方法名,改用表达式树实现编译期类型检查,杜绝拼写错误:
// 重载方法,支持表达式指定目标方法 private void Then_WirelessDeviceInvokedMethod( ushort unitId, Expression<Action<IWirelessDevice>> methodExpr, int expectedCallCount = 1) { var wdm = GetWirelessDeviceMock(unitId); var mock = wdm as Mock<IWirelessDevice>; Assert.That(mock, Is.Not.Null); mock.Verify(methodExpr, Times.Exactly(expectedCallCount)); } // 使用示例 Then_WirelessDeviceInvokedMethod(unitId, x => x.Connect("device-001"), 1);
4. 细节优化
- 用
??空合并运算符简化expectedArgs的空值处理 - 为断言添加明确的失败提示,降低调试成本
- 补充
methodName为空场景的处理逻辑
内容的提问来源于stack exchange,提问作者Hamza
相关产品推荐
相关产品推荐

