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

集成测试中无法在模拟InMemory数据库植入种子数据

集成测试中InMemory数据库种子数据不生效问题

问题说明

编写了包含集成测试的测试类,调用简单API接口。Setup方法中替换真实数据库为InMemory数据库并添加两个城市数据,但测试调用接口时种子数据未显示,测试失败。

测试类代码

public class TestControllerTest
{
    private WebApplicationFactory<RentAPI.Program> _factory;
    private HttpClient _client;

    [SetUp]
    public void Setup()
    {
        _factory = new WebApplicationFactory<RentAPI.Program>().WithWebHostBuilder(builder =>
        {
            builder.ConfigureTestServices(services =>
            {
                var dbContextDescriptor = services.SingleOrDefault(d =>
                    d.ServiceType == typeof(DbContextOptions<ApplicationDbContext>));

                services.Remove(dbContextDescriptor);

                services.AddDbContext<ApplicationDbContext>(options =>
                {
                    options.UseInMemoryDatabase(Guid.NewGuid().ToString());
                });

                using var scope = services.BuildServiceProvider().CreateScope();
                var db = scope.ServiceProvider.GetService<ApplicationDbContext>();

                SeedData(db);
            });
        });

        _client = _factory.CreateClient();
    }

    [Test]
    public async Task Test_test()
    {
        var response = await _client.GetAsync("/Test");
        var stingResult = await response.Content.ReadAsStringAsync();

        Assert.That(stingResult, Is.EqualTo("3"));
    }

    [TearDown]
    public void TearDown()
    {
        _client.Dispose();
        _factory.Dispose();
    }

    public static void SeedData(ApplicationDbContext context)
    {
        context.Cities.AddRange(
            new City { Id = 1, Name = "City1" },
            new City { Id = 2, Name = "City2" }
        );

        context.SaveChanges();
    }
}

API接口代码

[ApiController, Route("[controller]")]
public class TestController : ControllerBase
{
    private readonly IUnitOfWork _uow;

    public TestController(IUnitOfWork uow) => _uow = uow;

    [HttpGet]
    public async Task<ActionResult<string>> Test()
    {
        await _uow.CityRepository.AddAsync(new City() { Id = 99, Name = "Poko" });
        await _uow.CompleteAsync();

        var cities = await _uow.CityRepository.FindAllAsync();
        return cities.Count().ToString();
    }
}

测试失败结果

String lengths are both 1. Strings differ at index 0.
  Expected: "3"
  But was:  "1"
  -----------^

问题原因

你在配置InMemory数据库时,将Guid.NewGuid().ToString()写在了AddDbContext的配置委托内部。这个委托会每次创建DbContext实例时执行一次,导致种子数据使用的上下文和API接口使用的上下文连接的是两个不同的InMemory数据库,因此API无法读取到种子数据,最终只统计到自己添加的1条数据。

解决方案

提前生成固定的数据库名称,确保所有DbContext实例都连接同一个InMemory数据库:

修改测试类的Setup方法:

[SetUp]
public void Setup()
{
    // 提前生成唯一数据库名
    var dbName = Guid.NewGuid().ToString();

    _factory = new WebApplicationFactory<RentAPI.Program>().WithWebHostBuilder(builder =>
    {
        builder.ConfigureTestServices(services =>
        {
            var dbContextDescriptor = services.SingleOrDefault(d =>
                d.ServiceType == typeof(DbContextOptions<ApplicationDbContext>));

            services.Remove(dbContextDescriptor);

            // 使用提前生成的固定数据库名
            services.AddDbContext<ApplicationDbContext>(options =>
            {
                options.UseInMemoryDatabase(dbName);
            });

            using var scope = services.BuildServiceProvider().CreateScope();
            var db = scope.ServiceProvider.GetService<ApplicationDbContext>();

            SeedData(db);
        });
    });

    _client = _factory.CreateClient();
}

修改后,种子数据的上下文和API使用的上下文会连接同一个InMemory数据库,测试时接口会统计到2条种子数据+1条新增数据,返回结果为"3",测试通过。

内容的提问来源于stack exchange,提问作者Dmytro Kotenko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 16:20:23