单元测试遇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
相关产品推荐
相关产品推荐

