如何让CatalogDbContext仅在单元测试时执行HasData假数据填充?
仅在单元测试中为EF Core DbContext填充Bogus假数据的实现方案
要解决仅在单元测试时触发HasData假数据初始化,避免API运行时执行的问题,推荐以下几种实用方案:
方案1:通过构造函数参数控制测试模式
给CatalogDbContext添加标记测试环境的参数,在OnModelCreating中根据该参数决定是否加载假数据:
修改后的CatalogDbContext代码
using Bogus; using Catalog.Api.Database.Entities; using Microsoft.EntityFrameworkCore; namespace Catalog.Api.Database { public class CatalogDbContext : DbContext { private readonly bool _isTesting; // 生产环境使用默认构造重载,测试环境传入isTesting=true public CatalogDbContext(DbContextOptions<CatalogDbContext> options) : this(options, false) { } // 测试专用构造函数 public CatalogDbContext(DbContextOptions<CatalogDbContext> options, bool isTesting) : base(options) { _isTesting = isTesting; } public DbSet<CatalogItem> CatalogItems { get; set; } public DbSet<CatalogBrand> CatalogBrands { get; set; } public DbSet<CatalogType> CatalogTypes { get; set; } protected override void OnModelCreating(ModelBuilder builder) { builder.ApplyConfiguration(new CatalogBrandEntityTypeConfiguration()); builder.ApplyConfiguration(new CatalogTypeEntityTypeConfiguration()); builder.ApplyConfiguration(new CatalogItemEntityTypeConfiguration()); // 仅在测试模式下初始化假数据 if (_isTesting) { FakeData.Init(10); builder.Entity<CatalogItem>().HasData(FakeData.CatalogItems); } } } internal class FakeData { public static List<CatalogItem> CatalogItems = new List<CatalogItem>(); public static void Init(int count) { CatalogItems.Clear(); // 避免重复添加数据 var id = 1; var catalogItemFaker = new Faker<CatalogItem>() .RuleFor(ci => ci.Id, _ => id++) .RuleFor(ci => ci.Name, f => f.Commerce.ProductName()); // 生成指定数量的假数据并添加到列表 CatalogItems.AddRange(catalogItemFaker.Generate(count)); } } }
单元测试中的使用示例
// 测试项目中配置DbContext时传入isTesting=true var options = new DbContextOptionsBuilder<CatalogDbContext>() .UseInMemoryDatabase(databaseName: "TestCatalogDb") .Options; using var context = new CatalogDbContext(options, isTesting: true); context.Database.EnsureCreated(); // 此时假数据已自动填充到内存数据库中
方案2:创建测试专用DbContext子类
继承原有CatalogDbContext,仅在子类中添加假数据逻辑,API生产环境使用父类,测试环境使用子类:
测试项目中创建子类
using Catalog.Api.Database; using Microsoft.EntityFrameworkCore; namespace Catalog.Api.Tests.Database { public class TestCatalogDbContext : CatalogDbContext { public TestCatalogDbContext(DbContextOptions<CatalogDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { // 先执行父类的模型配置逻辑 base.OnModelCreating(builder); // 仅在此测试子类中添加假数据 FakeData.Init(10); builder.Entity<CatalogItem>().HasData(FakeData.CatalogItems); } } }
测试中的使用
var options = new DbContextOptionsBuilder<CatalogDbContext>() .UseInMemoryDatabase(databaseName: "TestCatalogDb") .Options; using var context = new TestCatalogDbContext(options); context.Database.EnsureCreated();
方案3:在测试配置中动态添加假数据
不修改原有CatalogDbContext,直接在测试项目中生成假数据并通过ModelBuilder添加:
测试代码示例
using Bogus; using Catalog.Api.Database.Entities; using Catalog.Api.Database; using Microsoft.EntityFrameworkCore; // 生成假数据 var id = 1; var catalogItemFaker = new Faker<CatalogItem>() .RuleFor(ci => ci.Id, _ => id++) .RuleFor(ci => ci.Name, f => f.Commerce.ProductName()); var fakeItems = catalogItemFaker.Generate(10); // 配置DbContext并添加假数据 var options = new DbContextOptionsBuilder<CatalogDbContext>() .UseInMemoryDatabase(databaseName: "TestCatalogDb") .Options; using var context = new CatalogDbContext(options); // 手动给模型添加假数据 context.ModelBuilder.Entity<CatalogItem>().HasData(fakeItems); context.Database.EnsureCreated();
关键注意事项
- 原代码中
FakeData.Init方法缺少将生成的假数据添加到CatalogItems列表的逻辑,已在方案1的代码中补充了CatalogItems.AddRange(catalogItemFaker.Generate(count))。 - 若使用内存数据库做单元测试,每次测试后建议调用
context.Database.EnsureDeleted()清空数据,避免测试间数据污染。
内容的提问来源于stack exchange,提问作者Tech with Thiru
相关产品推荐
相关产品推荐

