不可修改原类时,如何Mock非接口/非虚方法并设置返回值?
问题
如何对非接口、非虚方法的类执行Mock的Setup(...)和Returns(...)操作?约束条件:无法将目标类转为接口、无法将方法改为虚方法,且不可修改原类及方法,请求提供生成假数据的可行方案建议。
相关代码
public class Product { public int Sum(int a, int b) => a + b; } [TestMethod] public void SumTest() { var moc = new Mock<Product>(); moc.Setup(m => m.Sum(1, 1)).Returns(3); }
可行方案建议
使用商业隔离框架
像TypeMock Isolator、JustMock这类框架,能绕过.NET的访问限制,直接Mock非虚、非接口方法,无需修改原代码。以JustMock为例:[TestMethod] public void SumTest() { var mock = Mock.Create<Product>(); Mock.Arrange(() => mock.Sum(1, 1)).Returns(3); int result = mock.Sum(1, 1); Assert.AreEqual(3, result); }这类框架靠IL编织技术拦截方法调用,不过大多是商业付费软件。
用适配器模式创建包装类
不修改原类的前提下,给原类做一层包装,定义可Mock的接口,把原类的调用封装进去。示例:// 定义包装接口 public interface IProductWrapper { int Sum(int a, int b); } // 包装类,调用原Product的方法 public class ProductWrapper : IProductWrapper { private readonly Product _product; public ProductWrapper(Product product) { _product = product; } public int Sum(int a, int b) { return _product.Sum(a, b); } } // 测试代码 [TestMethod] public void SumTest() { var mockWrapper = new Mock<IProductWrapper>(); mockWrapper.Setup(m => m.Sum(1, 1)).Returns(3); int result = mockWrapper.Object.Sum(1, 1); Assert.AreEqual(3, result); }这种方式属于常规架构适配,完全免费,也符合代码设计原则。
反射+IL注入替换方法实现(临时方案)
通过反射结合IL注入库(如Harmony)修改原方法的实现逻辑,替换成自定义的假数据逻辑。示例思路:// 初始化Harmony实例 var harmony = new Harmony("test.product.sum.patch"); // 获取原方法的MethodInfo MethodInfo sumMethod = typeof(Product).GetMethod("Sum", BindingFlags.Public | BindingFlags.Instance); // 替换方法实现 harmony.Patch(sumMethod, postfix: new HarmonyMethod(typeof(SumPatch).GetMethod("OverrideSumResult"))); // 自定义替换逻辑类 public static class SumPatch { public static void OverrideSumResult(int a, int b, ref int __result) { // 当参数为1和1时,强制返回3 if (a == 1 && b == 1) { __result = 3; } } }这种方式复杂度高,容易污染测试环境,仅适合临时应急使用,测试后要注意清理注入的代码。
内容的提问来源于stack exchange,提问作者denis
相关产品推荐
相关产品推荐

