.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
相关产品推荐
相关产品推荐

