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

如何在XUnit集成测试中注入IDbContextFactory?

问题

我正在开发Blazor Server项目,创建了一个使用IDbContextFactory而非普通DbContext的泛型数据服务,该服务通过EntityFrameworkCore与数据库交互。需要为该服务编写使用真实测试数据库的XUnit集成测试,因此不打算Mock工厂。

服务基础结构如下:

public class CatalogService<T> : IEntityService<T> where T : CatalogBase
{
    private readonly IDbContextFactory<ApplicationDbContext> _contextFactory;
    private readonly ILogger<T> _logger;

    // 工厂通过构造函数注入
    public CatalogService(IDbContextFactory<ApplicationDbContext> contextFactory, ILogger<T> logger)
    {
        _contextFactory = contextFactory;
        _logger = logger;
    }    
    //... 所有功能方法
}

我编写了用于生成测试数据的Fixture:

public class TestDatabaseFixture
{
    private const string ConnectionString = @"my_connection";

    private static readonly object _lock = new();
    private static bool _databaseInitialized;

    public TestDatabaseFixture()
    {
        lock (_lock)
        {
            if (!_databaseInitialized)
            {
                using (var context = CreateContext())
                {
                    context.Database.EnsureDeleted();
                    context.Database.EnsureCreated();

                    // 创建品牌测试数据
                    for (int i = 0; i < 100; i++) {
                        context.PcMarcas.Add(new PcBrand { Description = $"Brand {(i + 1).ToString("0000") }" });
                    }                      
                    
                    context.SaveChanges();
                }

                _databaseInitialized = true;
            }
        }
    }

    public ApplicationDbContext CreateContext()
    { 
        return new ApplicationDbContext(
        new DbContextOptionsBuilder<ApplicationDbContext>()
            .UseSqlServer(ConnectionString)
            .Options);
    }

    public IDbContextFactory<ApplicationDbContext> CreateDbContextFactory() { 
        // 如何返回上下文工厂? <---
    }
}

测试代码如下:

[Fact]
public async Task GetAsync_ShouldReturnAnItem()
{
    // 初始化 ------------------------------------------------------
    var contextFactory = Fixture.CreateDbContextFactory(); // 来自Fixture

    var logger = Mock.Of<ILogger<PcMarca>>();
    var service = new CatalogService<PcMarca>(contextFactory, logger);

    // 执行  -------------------------------------------------------

    // 断言  ----------------------------------------------------
}

请问该如何实现CreateDbContextFactory方法,从而在XUnit集成测试中注入IDbContextFactory?

解决方案

你可以通过两种方式实现CreateDbContextFactory方法,核心都是返回一个符合IDbContextFactory<ApplicationDbContext>接口的实例,使其能创建连接到测试数据库的ApplicationDbContext。

方法1:使用EF Core内置的DbContextFactory

EF Core提供了内置的DbContextFactory<TContext>类,直接传入测试数据库的DbContextOptions即可完成实现:

public IDbContextFactory<ApplicationDbContext> CreateDbContextFactory() 
{
    var options = new DbContextOptionsBuilder<ApplicationDbContext>()
        .UseSqlServer(ConnectionString)
        .Options;

    return new DbContextFactory<ApplicationDbContext>(options);
}

注意:确保你的ApplicationDbContext类有一个接收DbContextOptions<ApplicationDbContext>参数的构造函数(通常EF Core脚手架生成的上下文默认包含该构造函数)。

方法2:自定义IDbContextFactory实现

如果需要更灵活的控制,可以自己实现IDbContextFactory接口:

public IDbContextFactory<ApplicationDbContext> CreateDbContextFactory() 
{
    var options = new DbContextOptionsBuilder<ApplicationDbContext>()
        .UseSqlServer(ConnectionString)
        .Options;

    return new TestDbContextFactory(options);
}

// 内部自定义工厂类
private class TestDbContextFactory : IDbContextFactory<ApplicationDbContext>
{
    private readonly DbContextOptions<ApplicationDbContext> _options;

    public TestDbContextFactory(DbContextOptions<ApplicationDbContext> options)
    {
        _options = options;
    }

    public ApplicationDbContext CreateDbContext()
    {
        return new ApplicationDbContext(_options);
    }
}

测试代码说明

实现CreateDbContextFactory后,你的测试代码就能正常获取工厂实例并注入到CatalogService中。Fixture里的静态锁和_databaseInitialized确保测试数据库只会初始化一次,所有测试用例共享同一套测试数据,提升测试效率。

内容的提问来源于stack exchange,提问作者Omar Yafer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 20:21:42