首页 > 解决方案 > 如何运行自定义 docker 镜像 testContainer

问题描述

我浏览了多个博客和官方文档,但无法解决我的问题。我正在使用testContainers-scala 版本 0.38.1scala 版本 2.11

我正在尝试使用 testContainer-scala 创建一个简单的测试,如下所示:

class MyServiceITSpec extends AnyFlatSpec with ForAllTestContainer {
  override val container = GenericContainer(dockerImage="my-service",
    exposedPorts = Seq(8080),
    env=(HashMap[String, String]("PARAM1" -> "value1", "PARAM2" -> "value2", "PARAM3" -> "value3")),
    waitStrategy = Wait.forHttp("/")
  )

  "GenericContainer" should "start my service and say Hello! Wassupp" in {
    assert(Source.fromInputStream(
      new URL(s"http://${container.containerIpAddress}:${container.mappedPort(8080)}/").openConnection().getInputStream
    ).mkString.contains("Hello! Wassupp"))
  }
}

基于以上片段,我的理解是这样的(如有错误请指正):

  1. 端口 8155 由 docker 容器公开,并且将分配一个针对该端口的随机主机端口。
  2. 我们可以将分配的端口作为 container.mappedPort

在这里,我试图断言http://localhost:mappedPort/返回Hello!瓦苏普

但是,我收到以下错误:

Caused by: org.testcontainers.containers.ContainerLaunchException: Could not create/start container
  at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:498)
  at org.testcontainers.containers.GenericContainer.lambda$doStart$0(GenericContainer.java:325)
  at org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:81)
  ... 18 more
Caused by: org.testcontainers.containers.ContainerLaunchException: Timed out waiting for URL to be accessible (http://localhost:32869/ should return HTTP 200)
  at org.testcontainers.containers.wait.strategy.HttpWaitStrategy.waitUntilReady(HttpWaitStrategy.java:214)
  at org.testcontainers.containers.wait.strategy.AbstractWaitStrategy.waitUntilReady(AbstractWaitStrategy.java:35)
  at org.testcontainers.containers.GenericContainer.waitUntilContainerStarted(GenericContainer.java:890)
  at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:441)
  ... 20 more

相同的图像运行得很好:

docker run -p 8081:8080 -e PARAM1=value1 -e PARAM2=value2 -e PARAM3=VALUE3 my-service

标签: scalaintegration-testingtestcontainers

解决方案


因此,在处理了错误之后,我发现了我的问题。这与请求中缺少所需的请求标头有关。我正在为遇到类似问题的任何人添加参考代码。

import com.dimafeng.testcontainers.{ForAllTestContainer, GenericContainer}
import org.scalatest.flatspec.AnyFlatSpec
import org.testcontainers.containers.wait.strategy.Wait

import scala.collection.immutable.HashMap
import scalaj.http.Http



    class MyServiceITSpec extends AnyFlatSpec with ForAllTestContainer {
      override val container = GenericContainer(dockerImage="my-service-img:tag12345",
        exposedPorts = Seq(8080),
        env=(HashMap[String, String]("PARAM1" -> "value1", "PARAM2" -> "value2")),
        waitStrategy = Wait.forHttp("/") // or "/health" based on ur implementation 
      )
    
      "My Service" should "successfully fetch the msg" in {
        assert(Http(s"http://${container.containerIpAddress}:${container.mappedPort(8080)}/products/product1")
          .header("HEADER1", "value1")
          .header("HEADER2", "value2")
          .asString.code==200)
      }
    
    }

经过大量阅读,我找到了一些解释:

  1. 您将docker应用程序公开的端口号作为暴露端口。
  2. TestContainers 然后将此端口映射到随机端口(这是为了避免端口号冲突而设计的)。如果你要直接在你的机器上运行这个 docker 镜像,你会写:

docker run -p 8081:8080 -e PARAM1=value1 -e PARAM2=value2 my-service-img:tag12345

在这里,您的公开端口是 8080映射端口是 8081

  1. TestContainers 通过暴露 8080 端口然后将其映射到随机端口来运行 docker 映像。映射端口可以是container.mappedPort()

  2. 另一个需要注意的重要事情是等待策略。这告诉代码等待,除非/端点启动。这是您的应用程序公开的一种健康检查。你可以有一个更好的端点来做同样的事情/health。默认情况下,它会等待60 秒以使该端点变为活动状态。发布它无论如何都会运行测试,如果应用程序到那时还没有启动,它会导致错误。我不确定如何覆盖默认超时,但我认为应该有办法做到这一点。

  3. 最后,我scalaj.http.Http用来发出 HTTP 请求(这是一个非常容易使用的请求 - 你可以)。


推荐阅读