使用Moq模拟EF Core DbContext时Set方法返回DbSet为null如何解决
如何用Moq为EF Core的DbContext模拟创建空DbSet
你遇到的返回null的原因是未对模拟DbContext的Set<T>()方法做返回配置,Moq对未配置的方法默认返回null。你可以按照以下步骤实现:
第一步:封装通用模拟DbSet创建方法
private Mock<DbSet<T>> CreateMockDbSet<T>(List<T> sourceData = null) where T : class { sourceData ??= new List<T>(); var queryable = sourceData.AsQueryable(); var mockSet = new Mock<DbSet<T>>(); // 配置IQueryable接口实现,支持常规LINQ查询 mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider); mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression); mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType); mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator()); // 配置AddRange方法实现,支持写入模拟数据 mockSet.Setup(m => m.AddRange(It.IsAny<IEnumerable<T>>())).Callback<IEnumerable<T>>(entities => sourceData.AddRange(entities)); // 可根据需求自行扩展Add、Remove、Find等方法的模拟逻辑 return mockSet; }
第二步:修改原有上下文模拟方法
private Mock<RealDBContext> GetDbContextMock() { var realDB= new RealDBContext(); var dbContextMock = new Mock<RealDBContext>(); dbContextMock.SetupAllProperties(); dbContextMock.Object.SomeTable1 = realDB.SomeTable1; dbContextMock.Object.SomeTable2 = realDB.SomeTable2; // 创建空的SomeTable3模拟DbSet var mockSomeTable3Set = CreateMockDbSet<SomeTable3Model>(); // 配置DbContext.Set<SomeTable3Model>()返回模拟DbSet dbContextMock.Setup(x => x.Set<SomeTable3Model>()).Returns(mockSomeTable3Set.Object); // 为上下文的SomeTable3属性赋值 dbContextMock.Object.SomeTable3 = mockSomeTable3Set.Object; // 此时AddRange可正常写入模拟数据 dbContextMock.Object.SomeTable3.AddRange(GetMockSomeTable3ModelList()); return dbContextMock; }
补充说明
如果需要支持EF Core的异步查询方法(如ToListAsync、FirstOrDefaultAsync等),需要额外为模拟DbSet配置IAsyncEnumerable<T>接口的对应实现,避免异步调用抛出异常。
内容的提问来源于stack exchange,提问作者CodeMonkey
相关产品推荐
相关产品推荐

