You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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();

关键注意事项

  1. 原代码中FakeData.Init方法缺少将生成的假数据添加到CatalogItems列表的逻辑,已在方案1的代码中补充了CatalogItems.AddRange(catalogItemFaker.Generate(count))。
  2. 若使用内存数据库做单元测试,每次测试后建议调用context.Database.EnsureDeleted()清空数据,避免测试间数据污染。

内容的提问来源于stack exchange,提问作者Tech with Thiru

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 00:21:25