集成测试项目多数据库配置异常:SQLite提示表不存在
问题解决方案
问题根源
你遇到的SQLite Error 1: 'no such table'错误,核心原因是:
- 原
MyDbContext的构造逻辑没有兼容测试环境的DI注入方式,导致它没有使用共享的内存连接,可能创建了独立的新内存数据库(无表结构); - 两个
DbContext的表创建时机或作用域不匹配,导致某一方的表未被初始化到共享数据库中。
同时要注意SQLite内存库的特性:同一个连接对应同一个内存数据库,连接关闭后数据库立即销毁,你已保持连接打开的操作是正确的。
具体修复步骤
1. 修正MyDbContext构造函数
确保它同时支持生产环境的自定义构造和测试环境的DI注入:
public class MyDbContext : DbContext { // 生产环境使用:通过工厂传入连接字符串和Schema public MyDbContext(DbContextOptions<MyDbContext> options, string connectionString, string schemaName) : base(options) { ModelBuilder.HasDefaultSchema(schemaName); // 可在此处补充连接字符串的自定义逻辑 } // 测试环境使用:直接接受DI注入的配置 public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { } // 你的DbSet定义和模型配置... }
2. 重构测试用AddSqlite扩展方法
确保两个DbContext都正确绑定到共享的内存连接:
internal static void AddSqlite(this IServiceCollection services) { // 移除原有的DbContext配置 var commonDbOpt = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<CommonDbContext>)); if (commonDbOpt != null) services.Remove(commonDbOpt); var myDbOpt = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<MyDbContext>)); if (myDbOpt != null) services.Remove(myDbOpt); // 移除原有的DbConnection注册 var dbConn = services.SingleOrDefault(d => d.ServiceType == typeof(DbConnection)); if (dbConn != null) services.Remove(dbConn); // 注册共享的内存连接,保持打开状态 services.AddSingleton<DbConnection>(sp => { var conn = new SqliteConnection("DataSource=:memory:"); conn.Open(); return conn; }); // 重新注册CommonDbContext services.AddDbContext<CommonDbContext>((sp, options) => { var conn = sp.GetRequiredService<DbConnection>(); options.UseSqlite(conn); }); // 重新注册MyDbContext services.AddDbContext<MyDbContext>((sp, options) => { var conn = sp.GetRequiredService<DbConnection>(); options.UseSqlite(conn); // 若需默认Schema,可在此配置: // options.UseSqlite(conn).UseSqlite(b => b.MigrationsHistoryTable("__EFMigrationsHistory", "dbo")); }); }
3. 调整TestDbContextFactory逻辑
确保返回的上下文是DI容器中正确配置的实例:
public class TestDbContextFactory : IDbContextFactory { private readonly IServiceProvider _serviceProvider; public TestDbContextFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public MyDbContext CreateMyDbContext(string? configKey, string? schemaName) { var context = _serviceProvider.GetRequiredService<MyDbContext>(); // 若需动态设置Schema,可在此补充逻辑(如Context有对应方法) // context.SetDefaultSchema(schemaName ?? "dbo"); return context; } }
4. 修正测试初始化方法
确保在同一个作用域内完成两个上下文的表创建和数据填充:
[SetUp] public void Setup() { using var scope = _webApplicationFactory.Services.CreateScope(); var scopedServices = scope.ServiceProvider; // 先获取两个上下文,确保共享同一连接 var commonDb = scopedServices.GetRequiredService<CommonDbContext>(); var myDb = scopedServices.GetRequiredService<MyDbContext>(); // 初始化两个上下文的表结构 commonDb.Database.EnsureCreated(); myDb.Database.EnsureCreated(); // 填充测试数据 SeedDataClass.InitializeDbForTests(commonDb); SeedDataClass.InitializeDbForTests(myDb); }
内容的提问来源于stack exchange,提问作者PalBo
相关产品推荐
相关产品推荐

