如何采用数据库优先方式配置Testcontainers?
用Testcontainers实现SQL Server数据库优先的集成测试方案
问题说明
- 要在集成测试中使用Testcontainers,但找不到数据库优先模式的配置方案,项目包含SQL Server的
.sqlproj文件,不知如何配置容器数据库 - 当前使用
await context.Database.EnsureCreatedAsync();仅能创建表,无法生成视图(因该方法基于DbContext,不会处理.sqlproj中定义的视图等非实体类数据库对象)
可行解决方案
方案一:执行.sqlproj编译生成的完整数据库脚本
.sqlproj编译后会生成包含所有数据库对象(表、视图、存储过程等)的SQL脚本,可在Testcontainers初始化时执行该脚本:
- 配置.sqlproj生成创建脚本:右键项目→属性→生成→勾选「生成创建脚本」,指定输出路径
- 在测试初始化阶段读取脚本并执行
修改InitializeAsync方法如下:
public async Task InitializeAsync() { await _container.StartAsync(); var masterConnectionString = _container.GetConnectionString(); var connectionStringBuilder = new SqlConnectionStringBuilder(masterConnectionString) { InitialCatalog = "master" }; // 创建目标数据库 using (var connection = new SqlConnection(connectionStringBuilder.ConnectionString)) { await connection.OpenAsync(); using (var command = new SqlCommand("CREATE DATABASE MyDatabase", connection)) { await command.ExecuteNonQueryAsync(); } } connectionStringBuilder.InitialCatalog = "MyDatabase"; var targetConnectionString = connectionStringBuilder.ConnectionString; // 读取并执行.sqlproj生成的数据库创建脚本 var scriptPath = Path.Combine(AppContext.BaseDirectory, "MyDatabaseCreationScript.sql"); var sqlScript = await File.ReadAllTextAsync(scriptPath); using (var connection = new SqlConnection(targetConnectionString)) { await connection.OpenAsync(); using (var command = new SqlCommand(sqlScript, connection)) { await command.ExecuteNonQueryAsync(); } } // 配置服务并构建容器 var serviceCollection = GetServices(targetConnectionString); ServiceProvider = serviceCollection.BuildServiceProvider(); }
方案二:基于EF Core迁移适配测试容器
若偏好使用EF Core的迁移机制,可从现有数据库(基于.sqlproj)生成迁移,再在测试中执行迁移:
- 从数据库生成DbContext和实体类:
Scaffold-DbContext "Server=.;Database=MyDatabase;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Context MyDbContext
- 生成初始迁移文件:
Add-Migration InitialCreate
- 在测试中用
MigrateAsync()替代EnsureCreatedAsync(),迁移会处理所有数据库对象:
修改初始化中的DbContext初始化代码:
using var scope = ServiceProvider.CreateScope(); var scopedServices = scope.ServiceProvider; var context = scopedServices.GetRequiredService<MyDbContext>(); // 执行迁移创建所有数据库对象 await context.Database.MigrateAsync();
代码优化建议
GetServices方法中重复注册了MyDbContext,可移除冗余注册:
private IServiceCollection GetServices(string connectionString) { var services = new ServiceCollection(); services.AddTransient<IMyServices, MyServices>(); services.AddDbContext<MyDbContext>(options => options.UseSqlServer(connectionString)); return services; }
内容的提问来源于stack exchange,提问作者ChinnMan Spam
相关产品推荐
相关产品推荐

