Skip to main content

AtomicJar, the maintainers of Testcontainers libraries, has released the Testcontainers Desktop app, which is a free companion app for open-source Testcontainers libraries that makes local development and testing with real dependencies simple.

You can read Testcontainers Desktop docs to learn various features offered by Testcontainers Desktop app. In this article, you will learn how to connect to the database(s) started by Testcontainers from any of your favourite database client tools.

Whether you run containers locally using container runtimes like Docker Desktop, OrbStack, etc., or on the cloud using Testcontainers Cloud, you can connect to the containerized services like databases, and message brokers using the Testcontainers Desktop port forwarding feature.

You might be working on a Microservices-based application where each service has its own database. And, you might want to run multiple microservices and connect to multiple databases to inspect the data.

In this blog post, let’s see how to use the Testcontainers Desktop port forwarding feature to connect to multiple containers of the same type (i.e., PostgreSQL).

Imagine we have two Spring Boot microservices, product-service, and promotion-service, which are using PostgreSQL as their database. We can use Spring Boot’s Testcontainers support to start PostgreSQL containers for both services. Now, we will learn how to use Testcontainers Desktop port forwarding feature to connect to the databases created by Testcontainers.

You can find the source code for this article at https://github.com/testcontainers-community/tcd-connecting-to-containers 

Create product-service

Create product-service using Spring Initializr by selecting Spring Web, Spring Data JPA, Flyway Migration, PostgreSQL Drive, and Testcontainers starters.

In the generated project, you can see TestProductServiceApplication.java under src/test/java as follows:

package com.testcontainers.products;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.utility.DockerImageName;

@TestConfiguration(proxyBeanMethods = false)
public class TestProductServiceApplication {

   @Bean
   @ServiceConnection
   PostgreSQLContainer<?> postgresContainer() {
       return new PostgreSQLContainer<>(DockerImageName.parse("postgres:16-alpine"));
   }

   public static void main(String[] args) {
       SpringApplication
               .from(ProductServiceApplication::main)
               .with(TestProductServiceApplication.class)
               .run(args);
   }
}

Now you can run TestProductServiceApplication.java from your IDE to start the application.

It will start a PostgreSQL database container using Testcontainers, configure the application to use that database, and apply the database migration script using Flyway.

Connecting to product-service database

When Testcontainers starts the PostgreSQL database container, it will map the database container’s port 5432 to a random available port on the host. So, it will be tedious to check every time what is the mapped port for the database container and then connect to it. Instead, we can use the Testcontainers Desktop port forwarding feature to map the container’s port to a fixed port on the host and connect to it.

Click on Testcontainers Desktop → select ServicesOpen config location.

In the opened directory there would be a postgres.toml.example file.

Rename it to products-postgres.toml file, and update it to the have the following configuration:

ports = [
   {local-port = 15432, container-port = 5432},
]
selector.image-names = ["postgres"]

In the above configuration, we have mapped the container’s port 5432 to the host’s port 15432.

Now when you restart the application, you should be able to connect to the database using the following details:

host: localhost
port: 15432
database: test
username: test
password: test

What if you want to connect to multiple containers of the same type?

Now you might be thinking, what if I have another microservice, say promotion-service, which also uses PostgreSQL as its database?

In the previous port forwarding configuration, we just configured the image selector as postgres which will match any PostgreSQL container. So, if you start the promotion-service, it will also use the same port mapping as product-service. This is where the labels selector comes into the picture.

Using Labels Selector

Let’s update the PostgreSQL container configuration in TestProductServiceApplication.java as follows:

@Bean
@ServiceConnection
PostgreSQLContainer<?> postgresContainer() {
   return new PostgreSQLContainer<>(
           DockerImageName.parse("postgres:16-alpine"))
           .withLabel("com.testcontainers.desktop.service", "products-postgres");
}

We have added a label com.testcontainers.desktop.service with the value products-postgres to the container. Now we can update the port forwarding configuration in products-postgres.toml file to match this label.

ports = [
 {local-port = 15432, container-port = 5432},
]

selector.image-names = ["postgres"]

[selector.labels]
"com.testcontainers.desktop.service" = "products-postgres"

In addition to the image selector, we have added a label selector to match the label com.testcontainers.desktop.service with the value products-postgres.

Now, assume that you have created the promotion-service which uses PostgreSQL similar to product-service, and you have TestPromotionServiceApplication.java under src/test/java as follows:

package com.testcontainers.promotions;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.utility.DockerImageName;

@TestConfiguration(proxyBeanMethods = false)
public class TestPromotionServiceApplication {

   @Bean
   @ServiceConnection
   PostgreSQLContainer<?> postgresContainer() {
       return new PostgreSQLContainer<>(
               DockerImageName.parse("postgres:16-alpine"))
               .withLabel("com.testcontainers.desktop.service", "promotion-postgres");
   }

   public static void main(String[] args) {
       SpringApplication
               .from(PromotionServiceApplication::main)
               .with(TestPromotionServiceApplication.class)
               .run(args);
   }
}

Now you can create a promotion-postgres.toml file next to products-postgres.toml file with the following configuration:

ports = [
 {local-port = 25432, container-port = 5432},
]

selector.image-names = ["postgres"]

[selector.labels]
"com.testcontainers.desktop.service" = "promotion-postgres"

In the above configuration, we have mapped the container’s port 5432 to the host’s port 25432.Now when you start the promotion-service application, you should be able to connect to the promotion-service database using the following details:

host: localhost
port: 25432
database: test
username: test
password: test

Though we have demonstrated connecting to the PostgreSQL database container, the same approach works for any other container such as Kafka, RabbitMQ, MongoDB, etc.

Summary

We have explored the Testcontainers Desktop port forwarding feature with a realistic scenario.

We have demonstrated how to use Testcontainers Desktop features using Java/SpringBoot examples, but it works for other Testcontainers supported languages (Go, .NET, Node.js, Python, etc) as well.

You can go to https://testcontainers.com/desktop/, download the Testcontainers Desktop application, and start using it for your application’s local development and testing.

Siva Katamreddy

Siva Katamreddy is a Developer Advocate at AtomicJar sharing the awesomeness of Testcontainers and helping the developers to build and release their software with confidence. He is a published author, and has written multiple books on Java technologies.