I'm writing integration tests using Testcontainers in a Spring Boot application. I am testing the user service, which calls the authentication service in order to encode the password when a user is created, and I'm trying to start two containers:
A postgres:17 database
A custom-built auth-service:latest container
The Postgres container starts correctly, executes init.sql, and works perfectly.
However, the auth-service container fails with this error:
Wait strategy failed. Container exited with code 1
Caused by: java.net.ConnectException: Connection refusedWaiting for URL: http://localhost:56873/auth/health
...
Timed out waiting for URL to be accessible (http://localhost:56873/auth/health should return HTTP [200])
@SpringBootTest(
properties = {
"logging.level.org.springframework.security=DEBUG",
},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
@TestPropertySource(properties = {
"spring.jpa.hibernate.ddl-auto=create-drop",
})
class UserControllerIntegrationTests {
static Network network = Network.newNetwork();
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:17")
.withDatabaseName("testdb")
.withUsername("testuser")
.withPassword("testpass")
.withNetwork(network)
.withNetworkAliases("postgres-db");
@Container
static GenericContainer<?> authService = new GenericContainer<>("auth-service:latest")
.withExposedPorts(8080)
.withNetwork(network)
.withNetworkAliases("auth-service")
.waitingFor(Wait.forHttp("/auth/health")
.forStatusCode(200)
.withStartupTimeout(Duration.ofSeconds(20)));
static {
String initScriptPath = "./init.sql";
try {
MountableFile.forClasspathResource(initScriptPath);
System.out.println("✅ Testcontainers: Found init script on classpath: " + initScriptPath);
postgres.withInitScript(initScriptPath);
} catch (IllegalArgumentException e) {
System.err.println("❌ Testcontainers ERROR: Init script NOT found on classpath: " + initScriptPath);
throw new RuntimeException("Failed to locate database initialization script.", e);
}
}
@Autowired
private TestRestTemplate restTemplate;
@Value("${server.api.key}")
private String apiKey;
@Autowired
private UserRepository userRepository;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private TestHelper httpTestHelper;
@Autowired
private JwtService jwtService;
@Autowired
private JwtAuthFilter jwtAuthFilter;
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
registry.add("api.services.auth-service", () ->
"http://" + authService.getHost() + ":" + authService.getMappedPort(8080));
}
I'm not sure if it can help you fix your issue but I want to share with you.
Here are the steps you should follow step by step
1 ) Define Second
Postgres container
2 ) Env-vars for Auth-Service
pointing at that DB
3 ) Shared Network
and withNetworkAliases
4 ) Increased health‐check timeout
& validated path
5 ) Log dump in @BeforeAll
6 ) Dynamic property
source unchanged except for adding the mapped Auth URL
Here is the full code shown below
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = {
"logging.level.org.springframework.security=DEBUG"
}
)
@Testcontainers
@TestPropertySource(properties = {
"spring.jpa.hibernate.ddl-auto=create-drop"
})
public class UserControllerIntegrationTests {
// Shared Docker network for containers
static final Network network = Network.newNetwork();
// 1) User Service DB
@Container
static PostgreSQLContainer<?> userDb = new PostgreSQLContainer<>("postgres:17")
.withDatabaseName("testdb")
.withUsername("testuser")
.withPassword("testpass")
.withNetwork(network)
.withNetworkAliases("postgres-db")
.withInitScript("init.sql");
// 2) Auth Service DB
@Container
static PostgreSQLContainer<?> authDb = new PostgreSQLContainer<>("postgres:17")
.withDatabaseName("authdb")
.withUsername("authuser")
.withPassword("authpass")
.withNetwork(network)
.withNetworkAliases("auth-db");
// 3) Auth Service
@Container
static GenericContainer<?> authService = new GenericContainer<>("auth-service:latest")
.withNetwork(network)
.withNetworkAliases("auth-service")
.withEnv("SPRING_DATASOURCE_URL", "jdbc:postgresql://auth-db:5432/authdb")
.withEnv("SPRING_DATASOURCE_USERNAME", "authuser")
.withEnv("SPRING_DATASOURCE_PASSWORD", "authpass")
.withExposedPorts(8080)
.waitingFor(Wait.forHttp("/auth/health").forStatusCode(200).withStartupTimeout(Duration.ofSeconds(60)));
@Autowired
private TestRestTemplate restTemplate;
@Value("${server.api.key}")
private String apiKey;
// Add your repositories, services, helpers as needed
@Autowired
private UserRepository userRepository;
@Autowired
private HttpTestHelper httpTestHelper;
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", userDb::getJdbcUrl);
registry.add("spring.datasource.username", userDb::getUsername);
registry.add("spring.datasource.password", userDb::getPassword);
registry.add("api.services.auth-service", () ->
"http://" + authService.getHost() + ":" + authService.getMappedPort(8080)
);
}
@BeforeAll
static void dumpAuthLogs() {
System.out.println("=== AUTH SERVICE LOGS ===");
System.out.println(authService.getLogs());
}
@Test
void testCreateUserEncodedPassword() {
// Your test implementation here
}
}