使用Ninject时,如何基于接口模拟Entity Framework上下文?
模拟ILikvidoWebsitesApiContext接口的方案
没问题!要模拟你的ILikvidoWebsitesApiContext接口用于测试,最常用也最顺手的工具是Moq(.NET生态里最流行的模拟框架)。下面我一步步给你拆解实现步骤:
1. 先准备好依赖包
首先确保你在测试项目里安装了Moq包:
- 通过NuGet包管理器:
Install-Package Moq - 或者用.NET CLI命令:
dotnet add package Moq
如果想简化DbSet<T>的模拟工作,还可以安装Moq.EntityFrameworkCore辅助包,能省不少重复代码:
dotnet add package Moq.EntityFrameworkCore
2. 基础模拟步骤(不用辅助包)
假设你的ILikvidoWebsitesApiContext接口里包含DbSet<Product> Products { get; set; }这类集合属性,我们需要为每个DbSet模拟测试数据,再挂载到上下文接口的模拟实例上:
代码示例:
// 第一步:准备测试用的实体数据 var testProducts = new List<Product> { new Product { Id = 1, Name = "测试商品1" }, new Product { Id = 2, Name = "测试商品2" } }.AsQueryable(); // 第二步:模拟DbSet<Product> var mockProductsDbSet = new Mock<DbSet<Product>>(); // 让DbSet实现IQueryable的必要成员 mockProductsDbSet.As<IQueryable<Product>>().Setup(m => m.Provider).Returns(testProducts.Provider); mockProductsDbSet.As<IQueryable<Product>>().Setup(m => m.Expression).Returns(testProducts.Expression); mockProductsDbSet.As<IQueryable<Product>>().Setup(m => m.ElementType).Returns(testProducts.ElementType); mockProductsDbSet.As<IQueryable<Product>>().Setup(m => m.GetEnumerator()).Returns(testProducts.GetEnumerator()); // 第三步:模拟你的上下文接口,把模拟好的DbSet挂载上去 var mockContext = new Mock<ILikvidoWebsitesApiContext>(); mockContext.Setup(c => c.Products).Returns(mockProductsDbSet.Object); // 如果接口里还有其他DbSet(比如Orders),重复上面的步骤模拟即可
3. 简化版模拟(用Moq.EntityFrameworkCore)
有了辅助包,模拟DbSet会轻松很多,不用手动设置IQueryable的所有成员:
// 准备测试数据 var testProducts = new List<Product> { new Product { Id = 1, Name = "测试商品1" }, new Product { Id = 2, Name = "测试商品2" } }; // 模拟上下文 var mockContext = new Mock<ILikvidoWebsitesApiContext>(); // 直接用ReturnsDbSet方法绑定测试数据 mockContext.Setup(c => c.Products).ReturnsDbSet(testProducts);
4. 在测试中使用模拟的上下文
把模拟好的上下文实例注入到你的服务里,就和生产环境中注入真实上下文一样:
// 创建服务实例,传入模拟的上下文 var productService = new ProductService(mockContext.Object); // 调用服务方法并验证结果 var allProducts = productService.GetAllProducts(); Assert.Equal(2, allProducts.Count());
额外:验证上下文方法的调用
如果你的服务会调用上下文的SaveChanges()之类的方法,还可以模拟并验证它的调用情况:
// 先模拟SaveChanges方法,设置返回值 mockContext.Setup(c => c.SaveChanges()).Returns(1); // 调用服务里的新增方法 productService.AddNewProduct(new Product { Name = "新商品" }); // 验证SaveChanges是否被调用了一次 mockContext.Verify(c => c.SaveChanges(), Times.Once);
内容的提问来源于stack exchange,提问作者Lars Holdgaard
相关产品推荐
相关产品推荐

