在 ASP.Net 集成测试中阻止 SQL 服务器连接

Prevent SQL Server Connection in ASP.Net Integration test

我有一个标准的 ASP.Net Web API 项目,其数据库设置如下所示:

Startup.cs

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

这按预期工作。

我还有一个集成测试设置,我尝试用内存中的服务器连接替换 SQL 服务器连接,以便每次测试都保持干净状态 运行:

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());
            });
    }
}

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

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

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

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

  1. 在具有持久性代码的 class 之上创建一个接口。由于您可能没有 class,因此也制作它并将代码移至
  2. 为您的界面创建模拟、存根或伪造以进行单元测试
  3. 使用 IoC 容器替换实现
  4. 将连接字符串加载移动到持久性实例化 class。这也可以通过 IoC 容器来完成

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

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

问题是 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");