You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#单元测试中替换构造函数内的Func委托

问题:单元测试中替换构造函数内调用的Func委托

原类代码

internal Func<...> MyFunc { get; set; }
public SomeClass(ISomeParam param)
    : base(param)
{
    MyFunc = MyMethod;
    MyPropertyX = MyFunc(someOtherParams);
}

无效的测试写法

var SubjectUnderTest = new MyClass(testParams) {
    MyFunc = MyNewMethodInsteadOfThatOneInClass
};

这种写法无效的核心原因:对象初始化器的赋值操作是在构造函数完全执行完毕后才执行的。构造函数里调用MyFunc(someOtherParams)时,MyFunc还是被赋值为MyMethod的状态,之后才会替换成你设置的新委托,所以对构造函数内的调用没有任何影响。


可行解决方案

方案1:给构造函数增加重载,支持传入自定义Func

修改原类的构造函数,新增带可选参数的重载,优先使用传入的自定义委托,无传入则用默认的MyMethod:

public SomeClass(ISomeParam param, Func<...> customFunc = null)
    : base(param)
{
    MyFunc = customFunc ?? MyMethod;
    MyPropertyX = MyFunc(someOtherParams);
}

测试时直接传入自定义委托即可:

var sut = new SomeClass(testParam, MyNewMethodInsteadOfThatOneInClass);

方案2:通过子类重写方法(不修改原构造函数签名)

如果不想改动原有构造函数的API,可以把MyMethod改成虚方法,在测试中创建子类重写该方法:

  1. 修改原类中的MyMethod访问修饰符为protected virtual:
protected virtual ReturnType MyMethod(...)
{
    // 原有业务逻辑
}
  1. 测试项目中创建可测试的子类:
public class TestableSomeClass : SomeClass
{
    private readonly Func<...> _customFunc;

    public TestableSomeClass(ISomeParam param, Func<...> customFunc)
        : base(param)
    {
        _customFunc = customFunc;
    }

    protected override ReturnType MyMethod(...)
    {
        return _customFunc(...);
    }
}
  1. 测试时使用这个子类:
var sut = new TestableSomeClass(testParam, MyNewMethodInsteadOfThatOneInClass);

方案3:反射(不推荐)

如果无法修改原类代码,可尝试用反射替换委托,但这种方式依赖内部实现细节,维护成本高且容易出错,仅作为最后备选:

var sut = new SomeClass(testParam);
// 用反射获取MyFunc属性并赋值
var myFuncProperty = typeof(SomeClass).GetProperty("MyFunc", BindingFlags.Instance | BindingFlags.NonPublic);
myFuncProperty.SetValue(sut, MyNewMethodInsteadOfThatOneInClass);
// 注意:这种方式无法影响构造函数内的MyFunc调用,只能修改构造完成后的委托状态,若要影响构造过程需用更复杂的拦截手段,不推荐常规单元测试使用

内容的提问来源于stack exchange,提问作者JJJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 23:54:58