Scala项目中TestContainers调用Docker Compose启动失败的解决咨询
解决Testcontainers Docker Compose找不到的问题及测试代码修正
一、解决Docker Compose找不到的错误
报错核心是Testcontainers无法在PATH中找到docker-compose命令,分两种场景解决:
1. 使用新版Docker Desktop(已整合docker-compose)
新版Docker Desktop将docker-compose整合到Docker CLI中,命令变为docker compose(无横杠)。需设置环境变量让Testcontainers识别这个命令:
- 运行测试前执行:
export TESTCONTAINERS_DOCKER_COMPOSE_COMMAND="docker compose" - 或在项目
build.sbt中添加全局配置:javaOptions += "-DTESTCONTAINERS_DOCKER_COMPOSE_COMMAND=docker compose"
2. 使用旧版Docker(需独立安装docker-compose)
如果是旧版Docker Engine,需单独安装docker-compose工具,并确保它被添加到系统PATH环境变量:
- 安装后验证可用性:
能输出版本信息说明PATH配置正确。docker-compose --version
二、修正测试代码的逻辑问题
你的测试当前连接的是公共MQTT服务器broker.hivemq.com,并未使用Testcontainers启动的本地容器,需修改连接地址并调整异步逻辑:
class MqttClientFactoryTest extends AsyncFunSuite with Matchers with TestContainersForAll { implicit val ec: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global override type Containers = DockerComposeContainer override def startContainers(): DockerComposeContainer = { DockerComposeContainer .Def( composeFiles = new File( this.getClass.getClassLoader .getResource("docker-compose-mqtt.yaml") .getFile ), exposedServices = Seq(ExposedService(name = "mqtt5", port = 1883)) ) .start() } test("mosquitto container") { withContainers { container => // 获取本地容器的MQTT访问地址 val mqttHost = container.getServiceHost("mqtt5", 1883) val mqttPort = container.getServicePort("mqtt5", 1883) val client: Mqtt5AsyncClient = Mqtt5Client .builder() .identifier(UUID.randomUUID().toString) .serverHost(mqttHost) .serverPort(mqttPort) .buildAsync() // 先订阅再发布,保证消息能被接收 val subscribeFuture = client .subscribeWith() .topicFilter("test/topic") .qos(MqttQos.EXACTLY_ONCE) .callback(x => println(new String(x.getPayloadAsBytes))) .send() .asScala val publishFuture = subscribeFuture.flatMap { _ => client .connect() .thenCompose(_ => client .publishWith() .topic("test/topic") .payload("some random message!!!".getBytes) .send() ) .asScala } // 组合异步操作,确保测试等待所有流程完成 publishFuture.map { _ => 1 should be(1) } } } }
代码修正说明:
- 通过
container.getServiceHost和container.getServicePort获取本地容器的实际访问地址 - 调整执行顺序为先订阅再发布,避免消息丢失
- 组合Future对象,确保测试不会提前结束
内容的提问来源于stack exchange,提问作者joesan
相关产品推荐
相关产品推荐

