在ASP.Net集成测试中阻止SQL Server连接



我有一个标准的ASP.NetWebneneneba API项目,它的DB设置看起来像这样:

启动.cs

services.AddDbContext<ProjectDbContext>(opts =>
opts.UseSqlServer(Configuration.GetConnectionString("ProjectDb")));

这符合预期。

我还有一个集成测试设置,在那里我尝试用内存中的连接来替换SQL Server连接,以便在每次测试运行时都进行一次全新的设置:

ProjectWebApplicationFactory.cs

public class ProjectWebApplicationFactory : WebApplicationFactory<Startup> {
protected override void ConfigureWebHost(IWebHostBuilder builder) {
builder.ConfigureServices(services => {
var prodDb = services.SingleOrDefault(s => s.ServiceType == typeof(ProjectDbContext));
services.Remove(prodDb);
services.AddDbContext<ProjectDbContext>(opts => {
opts.UseInMemoryDatabase(Guid.NewGuid().ToString());
});
}
}

在本地运行时,此操作再次正常工作。然而,当将此代码推送到构建/测试服务器时,它开始失败。初始SQL Server DB上下文尝试在被内存版本替换之前连接到数据库。由于服务器在本地可用,但在测试服务器上不可用,这会导致所有集成测试在运行之前都会失败。

在运行集成测试时,防止SQL Server上下文尝试连接的正确方法是什么?

问题是ProjectWebApplicationFactory.cs中的拼写错误

此行:

var prodDb = services.SingleOrDefault(s => s.ServiceType == typeof(ProjectDbContext));

应该是:

var prodDb = services.SingleOrDefault(s => s.ServiceType == typeof(DbContextOptions<ProjectDbContext>));

SQL服务器数据库在运行集成测试时仍在使用。这导致它不会在启动时失败,而是在实际调用端点时失败。

同样相关的是,内存中的数据库不应使用随机的Guid字符串创建,而应使用静态值,例如

opts.UseInMemoryDatabase("ProjectDb");

您正在进行集成测试,但不使用项目中的连接字符串。这意味着您已经使用生产数据库设置了API?如果是这样,就不要那样做。

我处理这个问题的方法是使用一些技术,所有这些技术都是为了反转依赖关系而设计的。

  1. 在具有持久性代码的类的顶部创建一个接口。由于您不太可能有一个类,所以也要创建它并将代码移到上面
  2. 为单元测试的接口创建mock、stub或fake
  3. 使用IoC容器交换实现
  4. 将连接字符串加载移动到持久性类的实例化。这也可以通过IoC容器来完成

这使您可以灵活地在任何地方进行集成测试,并避免在应用程序中嵌入生产字符串(如果您已经这样做的话(。

在这种情况下,你遵循了我经常看到的一些模式,但我发现,当你不了解问题的本质时,这种担忧的混合会导致问题。

最新更新