已实现FakeItEasy公共虚拟方法模拟,求指导模拟私有方法
嘿,得先给你划个重点:FakeItEasy 从设计初衷就不支持直接模拟私有方法——它的核心是帮你隔离公共/可重写的成员,私有方法属于类的内部实现细节,本来就不该直接被测试或模拟。不过咱们有两种可行的思路来解决你的问题,下面给你详细说:
方案1:重构代码(推荐,符合测试最佳实践)
最稳妥的方式是把私有方法里的核心逻辑抽成独立的可注入依赖,这样就能用FakeItEasy轻松模拟这个依赖的行为,间接实现对原私有逻辑的控制。
步骤1:定义处理核心逻辑的接口
把AddIntegers里的计算逻辑抽成一个接口:
public interface IIntegerCalculator { int CalculateValue(); }
步骤2:实现接口的真实逻辑
把原私有方法里的计算逻辑移到这个实现类里:
public class IntegerCalculator : IIntegerCalculator { public int CalculateValue() { int i = 3; int j = i * 100; int k = j * 30 / 100; return k; } }
步骤3:改造原XYZ类
通过构造函数注入上面的依赖,替换原私有方法的逻辑:
public class XYZ { public static int nValue = 0; private readonly IIntegerCalculator _calculator; // 构造函数注入依赖 public XYZ(IIntegerCalculator calculator) { _calculator = calculator; } // 假设原来有个公共方法触发私有逻辑,这里改成调用依赖 public void RunCalculation() { int k = _calculator.CalculateValue(); Show(string.Format("Value Here {0}", k.ToString())); nValue = k; } public virtual void Show(string message) { // 原方法实现 } }
步骤4:编写测试用例
现在就可以用FakeItEasy模拟依赖,控制计算结果,验证整个流程:
[Test] public void RunCalculation_ShouldSetCorrectNValue_WithMockedCalculator() { // 模拟计算器依赖,指定返回值 var mockCalculator = A.Fake<IIntegerCalculator>(); A.CallTo(() => mockCalculator.CalculateValue()).Returns(90); // 创建XYZ实例,注入模拟依赖 var xyz = new XYZ(mockCalculator); // 模拟Show方法(因为它是虚拟的) A.CallTo(() => xyz.Show(A<string>._)).DoesNothing(); // 执行测试方法 xyz.RunCalculation(); // 验证结果 Assert.AreEqual(90, XYZ.nValue); A.CallTo(() => mockCalculator.CalculateValue()).MustHaveHappenedOnceExactly(); A.CallTo(() => xyz.Show("Value Here 90")).MustHaveHappenedOnceExactly(); }
方案2:反射调用私有方法(仅应急使用)
如果实在没办法重构代码,你可以用.NET的反射机制直接调用私有方法,但这不是模拟私有方法,而是直接执行它的真实逻辑,只能用来验证结果,没法修改它的行为:
[Test] public void AddIntegers_ShouldSetNValue_Correctly() { var xyz = new XYZ(); // 通过反射获取私有方法 var addMethod = typeof(XYZ).GetMethod( "AddIntegers", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance ); // 模拟Show方法 A.CallTo(() => xyz.Show(A<string>._)).DoesNothing(); // 调用私有方法 addMethod.Invoke(xyz, null); // 验证静态字段的值 Assert.AreEqual(90, XYZ.nValue); A.CallTo(() => xyz.Show("Value Here 90")).MustHaveHappenedOnceExactly(); }
⚠️ 注意:这种方式是绕过封装直接操作内部逻辑,会让测试和实现细节绑定得很紧,后续代码改动很容易导致测试失败,所以非必要别用。
内容的提问来源于stack exchange,提问作者Sujeet Singh
相关产品推荐
相关产品推荐

