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

.NET Core 6中如何模拟带UnitOfWork与Repository的数据库访问?

解决FakeItEasy模拟TblageeventiRepository失败的方案

问题根源

这类错误通常源于以下情况:

  • TblageeventiRepository是具体类,且要模拟的Read/Update方法不是虚方法
  • UnitOfWork中的仓储属性未正确暴露,无法被FakeItEasy拦截
  • 未将仓储依赖抽象为接口,导致模拟能力受限

解决方案

1. 优先依赖抽象(推荐方案)

将仓储抽象为接口是依赖注入与单元测试的最佳实践:

  • 定义仓储接口ITblageeventiRepository,包含需模拟的方法:
    public interface ITblageeventiRepository
    {
        Tblageeventi Read(int id);
        void Update(Tblageeventi entity);
        // 其他业务所需方法
    }
    
  • 修改TblageeventiRepository实现该接口:
    public class TblageeventiRepository : ITblageeventiRepository
    {
        public Tblageeventi Read(int id) { /* 原有数据库操作逻辑 */ }
        public void Update(Tblageeventi entity) { /* 原有数据库操作逻辑 */ }
    }
    
  • 更新UnitOfWork,将仓储属性改为接口类型:
    public class UnitOfWork : IUnitOfWork
    {
        public ITblageeventiRepository TblageeventiRepo { get; }
        
        public UnitOfWork(ITblageeventiRepository tblageeventiRepo)
        {
            TblageeventiRepo = tblageeventiRepo;
        }
    }
    

2. 正确模拟仓储与UnitOfWork

基于接口编写测试代码,FakeItEasy可轻松模拟接口实例:

// 1. 模拟仓储接口并配置预期行为
var fakeRepo = A.Fake<ITblageeventiRepository>();
// 配置Read方法返回测试数据
A.CallTo(() => fakeRepo.Read(A<int>.Ignored))
  .Returns(new Tblageeventi { Id = 1, /* 填充测试用字段 */ });
// 配置Update方法的执行逻辑
A.CallTo(() => fakeRepo.Update(A<Tblageeventi>.Ignored))
  .DoesNothing();

// 2. 模拟UnitOfWork,让它返回已配置的模拟仓储
var fakeUnitOfWork = A.Fake<IUnitOfWork>();
A.CallTo(() => fakeUnitOfWork.TblageeventiRepo)
  .Returns(fakeRepo);

// 3. 调用目标工具方法
var utility = new UtilityOffPrenotazioni();
utility.UpdatePrenotazione(fakeUnitOfWork, /* 传入其他必要参数 */);

// 4. 验证方法是否按预期被调用
A.CallTo(() => fakeRepo.Update(A<Tblageeventi>.That.Matches(e => e.Id == 1)))
  .MustHaveHappenedOnceExactly();

3. 无法修改接口时的兼容方案(不推荐)

若因限制无法抽象接口,需确保仓储类的方法为虚方法——FakeItEasy仅能模拟非密封类的虚成员:

  • 修改TblageeventiRepository的方法为虚:
    public class TblageeventiRepository
    {
        public virtual Tblageeventi Read(int id) { /* 原有逻辑 */ }
        public virtual void Update(Tblageeventi entity) { /* 原有逻辑 */ }
    }
    
  • 模拟具体类并配置UnitOfWork:
    var fakeRepo = A.Fake<TblageeventiRepository>();
    A.CallTo(() => fakeRepo.Read(A<int>.Ignored)).Returns(new Tblageeventi { Id = 1 });
    
    var fakeUow = A.Fake<UnitOfWork>();
    A.CallTo(() => fakeUow.TblageeventiRepo).Returns(fakeRepo);
    
    // 调用工具方法并验证
    var utility = new UtilityOffPrenotazioni();
    utility.UpdatePrenotazione(fakeUow, /* 传入参数 */);
    
    A.CallTo(() => fakeRepo.Update(A<Tblageeventi>.Ignored)).MustHaveHappened();
    

4. 常见排查点

  • 检查UnitOfWork中的TblageeventiRepo属性是否为公共可访问属性,若为私有setter,FakeItEasy无法拦截,需改为public或用接口抽象
  • 确保工具方法UpdatePrenotazione中是通过传入的unitOfWork获取仓储,而非在方法内部直接实例化TblageeventiRepository

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 08:59:55