单元测试EF Core派生DbContext时遇无法创建Product的DbSet问题求助
解决DbContext单元测试中"Cannot create a DbSet for 'Product'"错误
问题场景
对CoreDbContext(DbContext派生类)做单元测试时,持续收到错误:
Cannot create a DbSet for 'Product' because this type is not included in the model for the context
测试代码
[Fact] public void GetAssync_Method_Called() { var options = new DbContextOptionsBuilder<CoreDbContext>() //.UseModel() USE MODEL .UseInMemoryDatabase(databaseName: "test") .Options; using (var context = new CoreDbContext(options)) { context.Set<Product>(); // 试图这样添加实体? Expression<Func<Product, bool>> filter = x => !x.IsDeleted == 1; var result = GetAllAsNoTrackin(filter); Assert.Equal(1, result.Count()); } }
CoreDbContext代码
public class CoreDbContext : DbContext { public CoreDbContext(DbContextOptions<CoreDbContext> options) : base(options) { } public IQueryable<Product> GetAllAsNoTrackin(Expression<Func<Product, bool>> filter) { var dbSet = Set<Product>().AsNoTracking(); // 报错位置 // 更多代码... } }
错误原因
EF Core的上下文模型中没有包含Product实体,调用Set<Product>()时无法识别该类型,导致报错。测试代码里的context.Set<Product>()并不能将实体添加到上下文模型中,模型是在上下文初始化阶段确定的。
解决方案
1. 显式声明DbSet属性
在CoreDbContext中添加DbSet<Product>属性,EF Core会自动将该实体纳入模型:
public class CoreDbContext : DbContext { public CoreDbContext(DbContextOptions<CoreDbContext> options) : base(options) { } // 添加DbSet属性,让EF Core识别Product实体 public DbSet<Product> Products { get; set; } public IQueryable<Product> GetAllAsNoTrackin(Expression<Func<Product, bool>> filter) { var dbSet = Set<Product>().AsNoTracking(); // 后续代码... } }
2. 在OnModelCreating中配置实体
如果不想显式声明DbSet,可以重写OnModelCreating方法,直接注册Product实体:
public class CoreDbContext : DbContext { public CoreDbContext(DbContextOptions<CoreDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { // 注册Product实体到模型 modelBuilder.Entity<Product>(); } public IQueryable<Product> GetAllAsNoTrackin(Expression<Func<Product, bool>> filter) { var dbSet = Set<Product>().AsNoTracking(); // 后续代码... } }
3. 使用UseModel方法(动态构建模型)
如果需要预先构建模型并传入上下文(替代OnModelCreating逻辑),可以这样使用UseModel:
[Fact] public void GetAssync_Method_Called() { // 先构建包含Product的模型 var modelBuilder = new ModelBuilder(); modelBuilder.Entity<Product>(); var model = modelBuilder.Model; var options = new DbContextOptionsBuilder<CoreDbContext>() .UseModel(model) // 使用预先构建的模型 .UseInMemoryDatabase(databaseName: "test") .Options; using (var context = new CoreDbContext(options)) { // 添加测试数据 context.Set<Product>().Add(new Product { IsDeleted = false }); context.SaveChanges(); Expression<Func<Product, bool>> filter = x => !x.IsDeleted; var result = context.GetAllAsNoTrackin(filter); Assert.Equal(1, result.Count()); } }
注意:UseModel是用来指定上下文使用的预构建模型,无法在上下文创建后动态添加实体,模型一旦确定就无法修改。
测试代码修正
确保上下文包含Product实体后,测试代码中需要添加测试数据才能验证逻辑:
[Fact] public void GetAssync_Method_Called() { var options = new DbContextOptionsBuilder<CoreDbContext>() .UseInMemoryDatabase(databaseName: "test") .Options; using (var context = new CoreDbContext(options)) { // 添加测试数据到上下文 context.Products.Add(new Product { IsDeleted = false }); context.SaveChanges(); Expression<Func<Product, bool>> filter = x => !x.IsDeleted; var result = context.GetAllAsNoTrackin(filter); Assert.Equal(1, result.Count()); } }
内容的提问来源于stack exchange,提问作者Richard77
相关产品推荐
相关产品推荐

