Testcontainer-01篇 基本入门

一、TestContainer是什么?

在我们开发的过程中,经常会用到一些第三方的产品或者中间件,如:redis,mq,db等等,然而,因为这些产品的引入,测试过程变得复杂起来,因为中间件的缺失(可能本地有,但是换了环境就没有了),导致测试用例编写很麻烦。
TestContainer可以通过和docker结合,让我们在编写测试用例的时候,很方便的启动docker容器(容器内有我们需要的第三方产品),这样,我们就可以更好的完善测试用例。

二、官方网站

https://www.testcontainers.org/

三、基本使用步骤

  1. 引入testcontainer依赖
      
        org.testcontainers
        testcontainers
        1.12.0
      
    
  2. 创建并启动容器,同时暴露端口
      @ClassRule
      public static GenericContainer redis = new GenericContainer("redis:5.0.5")
          .withExposedPorts(6379);
    
    实际上,new GenericContainer("redis:5.0.5")就会创建并启动容器,而withExposedPorts(6379)是用来暴露容器的端口号的,这些是对容器的一些配置,这种配置会有很多,后面再做介绍。
  3. 连接容器
    我们知道,在使用第三方产品的时候,会有一些配置项来连接这些产品,比如:redis需要指定主机和端口号,我们需要通过容器暴露出来的主机名和端口号进行连接。
    这可以通过以下两个方法:
  • 获取容器ip:redis.getContainerIpAddress()
  • 获取容器暴露的端口:redis.getMappedPort(6379)
  1. 编写测试代码
    有了连接的主机地址和端口,我们就可以连接redis进行redis操作了,这里redis创建连接及操作代码就省略了(因为后面我会给出完整的讲解,比如:在springboot环境下使用RedisTemplate的玩儿法)。
  2. 运行测试

四、常用操作

(一)端口暴露与获取

随机端口号

类似于启动命令的-P选项
暴露:
在创建容器的时候通过new GenericContainer(...).withExposedPorts(6379)方法可以将容器内使用的6379端口号暴露出来;
这种方式暴露出来的端口,在主机会有一个随机的端口号进行映射,
获取:
由于是随机的,所以我们无法在测试代码中提前写死要连接的端口号,这需要我们通过以下的方法来获取主机上与容器内对应的端口号,这有两种方法:

  1. container.getFirstMappedPort():这会获取到第一个端口映射出来的端口,如果我们的容器中只暴露出来了一个端口(如redis的6379),这种方式比较好用。
  2. container.getMappedPort(int port):找到容器内port端口映射出来的端口,当有多个端口的时候,使用这种方式。

使用技巧:
在Spring项目中,我们通常通过配置文件来指定这些参数,如:spring.redis.port。可是,在项目启动之前,由于容器没有启动,我们并不知道这个端口是多少,那么就没法在配置文件中配置端口了,我们如下设置:

  @BeforeClass
  public static void init() {
    System.setProperty("spring.redis.host", redis.getContainerIpAddress());
    System.setProperty("spring.redis.port", redis.getFirstMappedPort().toString());
  }

注意这里使用的注解是@BeforeClass,这样,我们就可以在Spring容器中通过@Value("${spring.redis.port}")的方式获取到随机生成的端口了

指定端口号

类似启动命令的-p选项。
这种方式在暴露的同时进行了映射绑定。

new GenericContainer(...).withCreateContainerCmdModifier(
          cmd -> {
            //对主机端口和docker中的端口进行绑定,前面的是主机端口,后面的是docker中的端口
            cmd.withPortBindings(new PortBinding(Ports.Binding.bindPort(8000), new ExposedPort(6379)));
          })

这样的话,我们就可以在代码中明确的使用8000端口来访问redis了

(二)获取容器ip

container.getContainerIpAddress()方法即可,默认可以直接使用localhost

(三)暴露本机端口号给容器

`Testcontainers.exposeHostPorts(localServerPort)` ,这种用法可能不多

(四)运行命令

  1. 指定启动命令
    new GenericContainer(...).withCommand("redis-server --port 7777")
  2. 在容器内部运行命令
    container.execInContainer("touch", "/somefile.txt");
  3. 运行命令并获取结果
    Container.ExecResult lsResult = container.execInContainer("ls", "-al", "/");
    String stdout = lsResult.getStdout();
    int exitCode = lsResult.getExitCode();
    assertTrue(stdout.contains("somefile.txt"));
    assertTrue(exitCode == 0);
    

(五)指定环境变量

new GenericContainer(...).withEnv("API_TOKEN", "foo")

(六)映射数据卷和文件

new GenericContainer(...)
        .withClasspathResourceMapping("redis.conf",
                                      "/etc/redis.conf",
                                      BindMode.READ_ONLY)

(七)获取日志

有如下两种方式获取容器内的运行日志:

一次性获取

使用container.getLogs()方法会获取容器从启动到当前的日志字符串

动态输出

ToStringConsumer toStringConsumer = new ToStringConsumer();
container.followOutput(toStringConsumer, OutputType.STDOUT);

这里有一堆的Consumer,如:ToStringConsumer、Slf4jLogConsumer等等

你可能感兴趣的:(#,TestContainer)