使用Microsoft Fakes模拟数据库访问时遇同名方法引发模糊匹配异常
解决Microsoft Fakes伪造重载方法时的Ambiguous Match Exception问题
这个坑我之前维护遗留代码时也踩过——当类里存在同名重载方法时,Fakes默认无法自动识别你要伪造的具体是哪一个,所以才会抛出模糊匹配异常。既然不能修改遗留代码的方法名,咱们可以从Fakes的重载处理机制入手解决,下面是几个靠谱的方案:
1. 使用Fakes自动生成的重载专属委托
Microsoft Fakes在生成假程序集时,会为每个重载方法生成带有参数类型后缀的委托。比如你的GetValue有以下两个重载:
public int GetValue(string key); public string GetValue(int id);
那么Fakes会自动生成GetValueString(对应参数为string的重载)和GetValueInt32(对应参数为int的重载)这样的委托。你直接用这些带后缀的委托来伪造就行:
using (ShimsContext.Create()) { // 伪造静态方法的string参数重载 ShimYourDbClass.GetValueString = (key) => 999; // 如果是实例方法,写法是这样的 ShimYourDbClass.Instance.GetValueInt32 = (instance, id) => "fake_data"; // 这里执行你的单元测试逻辑 }
如果是自定义类型的参数,后缀会用类型的简化名称(比如GetValueUserModel对应参数为UserModel的重载),你可以在Shim类的智能提示里找到对应的委托名称。
2. 用反射指定具体方法签名(适合复杂重载场景)
如果遇到泛型重载、参数类型特别复杂的情况,或者Fakes生成的委托不好用,你可以通过反射获取目标方法的MethodInfo,再用SetMethod方法明确指定要伪造的重载:
using (ShimsContext.Create()) { // 获取目标重载方法:比如参数为List<string>的GetValue MethodInfo targetMethod = typeof(YourDbClass) .GetMethod("GetValue", new[] { typeof(List<string>) }); // 伪造静态方法 ShimYourDbClass.SetMethod(targetMethod, (instance, args) => "fake_result"); // 如果是实例方法,逻辑类似,instance参数就是当前对象实例 ShimYourDbClass.Instance.SetMethod(targetMethod, (instance, args) => 100); }
这里要注意:GetMethod方法的第二个参数是参数类型的数组,必须和目标重载的参数类型完全匹配(包括泛型参数的具体类型),否则会返回null。
3. 重新生成Fakes程序集
有时候如果Fakes程序集生成不完整(比如第一次生成后又新增了重载方法),会导致重载委托没有被正确生成。这时候你可以:
- 删除项目
obj\Debug\Fakes(或obj\Release\Fakes)目录下的假程序集文件; - 右键点击主程序集的Fakes引用,选择“重新生成Fakes程序集”;
- 然后重新编译整个解决方案。
额外提醒
- 区分静态方法和实例方法的伪造写法:静态方法直接用
ShimClass.MethodXxx,实例方法要用ShimClass.Instance.MethodXxx; - 如果重载方法的参数是值类型和可空值类型(比如
int和int?),Fakes生成的委托后缀会区分开(比如GetValueInt32和GetValueNullableOfInt32),注意不要选错。
内容的提问来源于stack exchange,提问作者erhan355
相关产品推荐
相关产品推荐

