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

如何实现Mock类的继承复用?解决接口继承场景下Mock代码非DRY问题

解决Mock类继承复用的DRY问题

你遇到的这个问题确实很典型——当Mock继承接口时,直接继承Mock类会因为类型约束卡住,导致无法复用基类的Mock配置。下面给你几个实用的解决方案:

方案1:提取基类Mock配置到辅助方法

把Base接口的Mock配置逻辑抽成静态扩展方法,这样不管是BaseMock还是DerivedMock都可以调用,避免代码重复:

public static class BaseMockSetup
{
    public static void SetupBaseProperties<T>(this Mock<T> mock, int basePropertyValue) 
        where T : class, IBase
    {
        mock.SetupGet(o => o.BaseProperty).Returns(basePropertyValue);
    }
}

// BaseMock可以简化成这样
class BaseMock : Mock<IBase>
{
    public int BaseProperty { get; set; } = 42;

    public BaseMock()
    {
        this.SetupBaseProperties(BaseProperty);
    }
}

// DerivedMock不用重复Base的配置,只需要调用辅助方法+配置自己的属性
class DerivedMock : Mock<IDerived>
{
    public int BaseProperty { get; set; } = 42;
    public int DerivedProperty { get; set; } = 73;

    public DerivedMock()
    {
        this.SetupBaseProperties(BaseProperty);
        SetupGet(o => o.DerivedProperty).Returns(DerivedProperty);
    }
}

这个方案的好处是灵活,不管你的Mock类继承哪个接口,只要实现了IBase,就能复用Base的配置逻辑,完全符合DRY原则。

方案2:使用泛型基类Mock

把BaseMock改成泛型类,约束泛型参数必须继承IBase,这样DerivedMock可以直接继承这个泛型类,同时保留对IDerived的类型支持:

// 泛型基类Mock,支持所有继承IBase的接口
class BaseMock<T> : Mock<T> where T : class, IBase
{
    public int BaseProperty { get; set; } = 42;

    public BaseMock()
    {
        SetupGet(o => o.BaseProperty).Returns(BaseProperty);
    }
}

// DerivedMock直接继承泛型BaseMock,指定类型为IDerived
class DerivedMock : BaseMock<IDerived>
{
    public int DerivedProperty { get; set; } = 73;

    public DerivedMock()
    {
        SetupGet(o => o.DerivedProperty).Returns(DerivedProperty);
    }
}

这个方案更符合面向对象的继承思想,DerivedMock自动获得了BaseMock的所有配置和属性,只需要专注于自己的DerivedProperty配置即可,代码最简洁。

方案3:组合代替继承(备选)

如果上面两种方案不适合你的场景,还可以用组合的方式:让DerivedMock包含一个BaseMock实例,然后把Base的属性委托给它,同时自己处理Derived的配置:

class DerivedMock : Mock<IDerived>
{
    private readonly BaseMock _baseMock;

    public int BaseProperty 
    { 
        get => _baseMock.BaseProperty; 
        set => _baseMock.BaseProperty = value; 
    }
    public int DerivedProperty { get; set; } = 73;

    public DerivedMock()
    {
        _baseMock = new BaseMock();
        // 复用BaseMock的Setup逻辑
        SetupGet(o => o.BaseProperty).Returns(BaseProperty);
        SetupGet(o => o.DerivedProperty).Returns(DerivedProperty);
    }
}

不过这个方案需要手动委托属性,不如前两个方案高效,适合一些特殊场景。

我个人更推荐方案2,它既保持了代码的复用性,又让Mock类的结构更清晰,完全解决了你之前的编译问题和重复代码问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 16:22:50