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

WebApplicationFactory无法为InMemoryDatabase测试设置初始数据

问题原因及解决方案

核心问题1:请求指向了真实API而非测试模拟主机

你在测试中使用的baseURLString = "https://localhost:7228/"是真实运行的API地址,而WebApplicationFactory.CreateClient()返回的HttpClient已经自动配置了测试模拟主机的基地址,你的请求实际发送到了外部API,而非测试用的模拟应用,自然看不到测试数据。

核心问题2:数据初始化在临时服务容器中

在ConfigureWebHost的ConfigureServices方法中调用services.BuildServiceProvider()会创建一个独立的临时服务容器,你在这里初始化的数据只存在于这个临时容器的内存数据库中,而测试应用实际使用的是后续构建的正式服务容器,两者上下文不共享(即使内存数据库名称相同,这种提前构建的方式也会导致状态不一致)。


修正后的代码

1. 修正测试基类BaseTestInitialziacion

移除硬编码的真实地址,直接使用相对路径访问测试主机:

namespace UnitTests_EternalCODEStudio_API.TestData2 {
    public class BaseTestInitialziacion {
        // 不需要指定真实地址,HttpClient已内置测试主机基地址
        protected string baseURLString = ""; 
        MyWebApplication WebApp = null!;
        protected HttpClient httpClient = null!;
        
        [TestInitialize]
        public void Setup() {
            WebApp = new MyWebApplication();
            httpClient = WebApp.CreateClient();
        }
    }
}

2. 修正MyWebApplication类

将数据初始化逻辑移到CreateHost方法中,使用主机的正式服务容器:

class MyWebApplication : WebApplicationFactory<Program> {
    protected override IHost CreateHost(IHostBuilder builder) {
        var host = base.CreateHost(builder);
        
        // 使用主机的服务容器初始化数据
        using(var scope = host.Services.CreateScope()) {
            var dbContext = scope.ServiceProvider.GetRequiredService<ECSContext>();
            dbContext.Database.EnsureDeleted();
            dbContext.Database.EnsureCreated();
            
            dbContext.TUsers.AddRange(TestDataProvider.GetSampleUsers());
            dbContext.TRoles.AddRange(TestDataProvider.GetSampleRoles());
            dbContext.TUsersroles.AddRange(TestDataProvider.GetSampleUsersAndRoles());
            
            int changesMade = dbContext.SaveChanges();
            Console.WriteLine($"ChangesMade: {changesMade}");
        }
        
        return host;
    }
    
    protected override void ConfigureWebHost(IWebHostBuilder builder) {
        builder.ConfigureServices(services => {
            // 移除原有数据库配置
            services.RemoveAll<DbContextOptions<ECSContext>>();
            
            // 添加内存数据库,使用固定或随机名称均可
            services.AddDbContext<ECSContext>(builder =>
            {
                builder.UseInMemoryDatabase(databaseName: "TestECSDb"); // 固定名称便于调试,也可以用Guid.NewGuid().ToString()
            });
        });
    }
}

3. 修正测试方法中的请求路径

确保使用相对路径:

[TestMethod]
public async Task Test_UserController_Login_OK() {
    UsersDTO_usernameAndPass userData = new UsersDTO_usernameAndPass {
        Username = "user1",
        Password = "Test!Password1"
    };
    StringContent jsonContent = new StringContent(JsonConvert.SerializeObject(userData), Encoding.UTF8, "application/json");

    // 使用相对路径,HttpClient会自动拼接测试主机基地址
    var response = await httpClient.PostAsync($"{baseURLString}Users/Login", jsonContent);

    Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}

额外说明

  • 内存数据库是按名称隔离的,同一个名称的数据库会被不同的ECSContext实例共享,所以固定名称有助于调试,使用随机名称则可以保证每个测试实例的数据库独立。
  • 移除dbContext.ChangeTracker.Clear(),因为在初始化数据前上下文是全新的,不需要清除跟踪器,反而可能导致数据保存异常。

内容的提问来源于stack exchange,提问作者Alex Ibrahim Ojea

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 08:25:05