首页 > 其他分享 >使用TestContainers在Docker中进行集成测试

使用TestContainers在Docker中进行集成测试

时间:2023-09-17 21:22:32浏览次数:36  
标签:集成 容器 TestContainers 实例 测试 Docker public

现代软件应用很少独立工作。典型的应用程序会与几个外部系统进行通信,如:

  • 数据库、
  • 消息系统、
  • 缓存提供商
  • 其他第三方服务。

你应该编写测试确保一切正常运行。

单元测试有助于隔离地测试业务逻辑,不涉及任何外部服务。它们易于编写并提供几乎即时的反馈。

有了单元测试还不够,集成测试用来验证与外部系统的交互情况,让你对你的应用程序完全有信心。

所以,在本周的时事通讯中,我将向你展示如何使用Docker进行集成测试。我们需要以下组件

  • TestContainers
  • Docker
  • xUnit

TestContainers是什么

Testcontainers 是一个用于使用临时 Docker 容器编写测试的库。

集成测试是“困难”的,因为你需要维护测试基础设施。在运行测试之前,你需要确保数据库已启动并正在运行。你还必须为测试提供所需的任何数据。如果你的测试在同一数据库上并行运行,它们可能会相互干扰。

一个可能的解决方案是使用所需服务的内存中变体。但这与使用mocks并没有太大的不同。内存中的服务可能没有生产服务的所有功能。

Testcontainers 通过使用 Docker 来启动真实服务来解决这个问题,以进行集成测试。

下面是创建 SQL Server 容器的示例:

MsSqlContainer dbContainer = new MsSqlBuilder()
    .WithImage("mcr.microsoft.com/mssql/server:2022-latest")
    .WithPassword("Strong_password_123!")
    .Build();

之后,你可以使用 MsSqlContainer 实例来获取运行在容器内部的数据库的连接。 这是一个真实的SQL Server数据库,而不是内存数据库。

自定义 WebApplicationFactory:

ASP.NET Core 提供了一个内存测试服务器,我们可以用它来启动一个应用程序实例来运行测试。Microsoft.AspNetCore.Mvc.Testing 包提供了我们将用作实现基础的 WebApplicationFactory 类。

WebApplicationFactory<TEntryPoint> 用于为集成测试创建一个 TestServer

IntegrationTestWebAppFactory 进行以下工作:

  • 创建并配置MySqlContainer实例
  • 调用ConfigureTestServices 用容器中的数据库来设置EF Core
  • 用IAsyncLifetime来控制容器实例的启动/停止
public class IntegrationTestWebAppFactory
    : WebApplicationFactory<Program>,
      IAsyncLifetime
{
    private readonly MsSqlContainer _dbContainer = new MsSqlBuilder()
        .WithImage("mcr.microsoft.com/mssql/server:2022-latest")
        .WithPassword("Strong_password_123!")
        .Build();

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureTestServices(services =>
        {
            var descriptorType =
                typeof(DbContextOptions<ApplicationDbContext>);

            var descriptor = services
                .SingleOrDefault(s => s.ServiceType == descriptorType);

            if (descriptor is not null)
            {
                services.Remove(descriptor);
            }

            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(_dbContainer.GetConnectionString()));
        });
    }

    public Task InitializeAsync()
    {
        return _dbContainer.StartAsync();
    }

    public new Task DisposeAsync()
    {
        return _dbContainer.StopAsync();
    }
}

MsSqlContainer 有一个 GetConnectionString 方法,用于获取当前容器的连接字符串。连接字符串可能会在测试之间发生变化,因为每个测试类都会创建一个单独的容器实例。在同一测试类中的测试案例将使用相同的容器实例。因此,如果你需要在测试之间进行清理,请记住这一点。

另一件事是Data Migration。你必须在每次测试之前显示运行,以创建所需的数据库结构。

使用 IAsyncLifetime 异步启动容器实例。在运行任何测试之前,容器是在 StartAsync 中启动的。而它是在 StopAsync 中停止的。

创建测试基类

测试基类将实现一个类固件接口 IClassFixture。并在测试用例之间提供共享的对象实例。这是实例化大多数测试所需的任何服务的地方。

例如,我正在创建一个 IServiceScope,用于在测试中解析scoped services。

  • ISender 用来发送command和queries
  • ApplicationDbContext 用来设置数据库或者验证结果
public abstract class BaseIntegrationTest
    : IClassFixture<IntegrationTestWebAppFactory>,
      IDisposable
{
    private readonly IServiceScope _scope;
    protected readonly ISender Sender;
    protected readonly ApplicationDbContext DbContext;

    protected BaseIntegrationTest(IntegrationTestWebAppFactory factory)
    {
        _scope = factory.Services.CreateScope();

        Sender = _scope.ServiceProvider.GetRequiredService<ISender>();

        DbContext = _scope.ServiceProvider
            .GetRequiredService<ApplicationDbContext>();
    }

    public void Dispose()
    {
        _scope?.Dispose();
        DbContext?.Dispose();
    }
}

 

现在万事俱备,可以写测试用例了。

编写测试用例

这里有一个ProductTests类,里面有一个集成测试的用例,我们使用Arragne, Act, Assert结构。

public class ProductTests : BaseIntegrationTest
{
    public ProductTests(IntegrationTestWebAppFactory factory)
        : base(factory)
    {
    }

    [Fact]
    public async Task Create_ShouldCreateProduct()
    {
        // Arrange
        var command = new CreateProduct.Command
        {
            Name = "AMD Ryzen 7 7700X",
            Category = "CPU",
            Price = 223.99m
        };

        // Act
        var productId = await Sender.Send(command);

        // Assert
        var product = DbContext
            .Products
            .FirstOrDefault(p => p.Id == productId);

        Assert.NotNull(product);
    }
}

 

结束语

Testcontainers 是使用 Docker 编写集成测试的出色解决方案。你可以启动并配置任何 Docker 镜像,并从你的应用程序中使用它。这比使用模拟或内存变体要好得多,它们缺乏许多功能。

如果你有一个支持 Docker 的 CI/CD 流水线,Testcontainers 将开箱即用。

有几个集成测试可以大大增强你对系统的信心。

 

 

标签:集成,容器,TestContainers,实例,测试,Docker,public
From: https://www.cnblogs.com/odyssey/p/17709833.html

相关文章

  • ⛳ Docker 安装、配置和详细使用教程-Win10专业版
    ⛳Docker安装、配置和详细使用教程-Win10专业版......
  • SSM框架集成
    步骤一:创建Mavenweb项目步骤二:添加pom.xml相关依赖包<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xs......
  • Docker-compose容器编排
    Docker容器编排的作用是管理和协调多个Docker容器的部署、启动、停止和扩展等操作。它可以确保应用程序在分布式环境中以可靠、高效和可伸缩的方式运行。1)安装步骤参考官网文档,选择对应的系统版本即可,官网提供两种安装方式请根据需要自行选择。https://docs.docker.com/desktop/in......
  • springcloud 集成rabbitmq
    以下是在SpringCloud中使用RabbitMQ的基本步骤:引入依赖:在pom.xml文件中引入以下依赖:<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bus-amqp</artifactId></dependency><depe......
  • docker常用的命令
    1、帮助类启动命令:启动docker:systemctlstartdocker停止docker:systemctlstopdocker重启docker:systemctlrestartdocker查看docker状态:systemctlstatusdocker开机启动:systemctlenabledocker查看docker概要信息:dockerinfo查看docker总体帮助文档:docker--he......
  • Docker 环境清理无用数据的方法?
    Docker让运维及开发部署变得容易了,正因为容易导致不经意的就在不断添加新的docker映像、容器等。这些都将占用了我们系统上的很多宝贵空间,又一直在快速地增加。以此我们有必要定期做下清理Docker环境,把一些不使用的Docker资源清理掉节省的空间出不来。查看本机磁盘空间大小[ro......
  • centos7.4安装docker
    文档安装连接:https://docs.docker.com/engine/install/centos/1、确定你是CentOS7及以上版本2、如果当前系统中有已经安装的版本,则卸载老版本:sudoyumremovedocker\docker-client\docker-client-latest\docker......
  • windows11右键集成新建markdown文件
    右键集成新建markdown文档在桌面新建文本文档输入以下内容WindowsRegistryEditorVersion5.00[HKEY_CLASSES_ROOT.md]@="Typora.exe"[HKEY_CLASSES_ROOT.md\ShellNew]"NullFile"=""[HKEY_CLASSES_ROOT\Typora.exe]@="Markdown"把后缀名改为.reg点击执行......
  • 模拟集成电路设计系列博客——2.1.3 两级放大器的补偿
    2.1.3两级放大器的补偿这一小节讨论了在闭环中使用放大器,以及如何来补偿放大器使得闭环不仅稳定,而且会有一些其他的良好特性。尽管使用两级放大器作为例子,但是这里讨论的情况大部分也可以用于其他的放大器。放大器的最优补偿一般被认为是放大器设计过程中中最困难的环节,但是采......
  • Windows 打包 Docker 提示环境错误: no DOCKER_HOST environment variable
    这个问题应该还是比较常见的。[ERROR]Failedtoexecutegoalio.fabric8:docker-maven-plugin:0.40.2:build(default)onprojectmq-service:Executiondefaultofgoalio.fabric8:docker-maven-plugin:0.40.2:buildfailed:No<dockerHost>given,noDOCKER_HOSTenviro......