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

单元测试遇System.NotSupportedException:RepositoryBase.FindAll无法Mock

解决Moq中设置不可重写仓储方法的错误

问题场景

我实现了三个核心功能:

  • GetBandsRangeMapping:关联BandsRange与BandsMappings生成BandsRangeMappings并缓存,用于高频查询
  • GetPredictionsFromJsonAsync:以正确JSON格式返回结果
  • GetBandsPredictions:返回预测数据

在使用Moq框架对IUnitOfWork等依赖进行Mock的单元测试中,设置Repository的FindAll方法时触发错误:

System.NotSupportedException : Unsupported expression: ... => ....FindAll()
Non-overridable members (here: RepositoryBase.FindAll) may not be used in setup / verification expressions.

问题根源

Moq只能Mock可重写的成员(抽象方法、虚方法,或者接口定义的方法)。如果RepositoryBase.FindAll是普通非虚方法,Moq无法拦截并设置其行为,就会抛出这个错误。

解决步骤

1. 为仓储定义抽象接口

给仓储类定义对应的接口,把FindAll方法声明在接口中:

public interface IBandsRangeRepository
{
    IEnumerable<BandsRange> FindAll();
}

// 仓储基类实现接口
public class RepositoryBase<T> : IBandsRangeRepository
{
    public IEnumerable<BandsRange> FindAll()
    {
        // 原有业务逻辑
    }
}

2. 依赖注入接口而非具体类

业务逻辑中依赖注入接口类型,而非具体的仓储基类:

public class BandsService
{
    private readonly IBandsRangeRepository _bandsRangeRepo;

    public BandsService(IBandsRangeRepository bandsRangeRepo)
    {
        _bandsRangeRepo = bandsRangeRepo;
    }

    // 调用_bandsRangeRepo.FindAll()的业务逻辑代码
}

3. 修改测试代码Mock接口

单元测试中直接Mock接口实例,而非具体仓储类:

// 创建接口的Mock实例
var mockRepo = new Mock<IBandsRangeRepository>();
// 设置FindAll的返回测试数据
mockRepo.Setup(repo => repo.FindAll()).Returns(new List<BandsRange> { /* 填充测试数据 */ });

// 将Mock实例注入业务服务
var service = new BandsService(mockRepo.Object);

备选方案:将FindAll改为虚方法

如果受限于现有架构无法改用接口,可以把RepositoryBase中的FindAll改为虚方法:

public class RepositoryBase<T>
{
    public virtual IEnumerable<T> FindAll()
    {
        // 原有逻辑
    }
}

这种方式能让Moq拦截方法,但灵活性不如接口Mock,仅作为临时过渡方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 05:07:02