Spring Boot
Kubernetes
Integration Testing
Testcontainers Alternatives
Containerized Testing

Options or alternatives to Testcontainers for Spring Boot integration testing in Kubernetes?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Testcontainers is a strong default for Spring Boot integration tests, but it is not the only option. The right alternative depends on what you are actually trying to validate: application behavior, infrastructure contracts, or Kubernetes deployment behavior.

Start by Testing the Right Layer

Many teams reach for Kubernetes too early. If the purpose of the test is "does my application talk to PostgreSQL and Redis correctly," a full cluster is often unnecessary. If the purpose is "does my Helm chart, service wiring, ingress, and readiness behavior work in a cluster," then Kubernetes becomes relevant.

A pragmatic split looks like this:

  • use in-process or local dependencies for fast repository and service tests
  • use container-based dependencies for realistic application integration tests
  • use a real cluster or local cluster for deployment and platform tests

That split keeps the feedback loop fast without pretending every test must simulate production.

Alternative 1: Spring Boot With Embedded or Stubbed Dependencies

For some services, a real external system is not necessary. A Spring Boot test can run against:

  • H2 for simple SQL repository tests
  • WireMock for HTTP integrations
  • fake S3 or local filesystem adapters

Example with WireMock:

java
1@SpringBootTest
2class CustomerClientTest {
3
4    static WireMockServer wireMock = new WireMockServer(8089);
5
6    @BeforeAll
7    static void startServer() {
8        wireMock.start();
9        wireMock.stubFor(get("/customers/42")
10            .willReturn(okJson("{\"id\":42,\"name\":\"Ada\"}")));
11    }
12
13    @AfterAll
14    static void stopServer() {
15        wireMock.stop();
16    }
17
18    @Test
19    void fetchesCustomer() {
20        String body = RestAssured.get("http://localhost:8089/customers/42")
21            .asString();
22        assertTrue(body.contains("Ada"));
23    }
24}

This is not a Kubernetes test, but it is often the fastest replacement when the original Testcontainers usage was too heavy for the value it provided.

Alternative 2: Docker Compose Integration Tests

If you still want real infrastructure but not per-test ephemeral containers, Docker Compose can be simpler. Spring Boot has good support for local service-backed development, and CI systems can start a compose stack before running the test suite.

This approach works well for:

  • one shared PostgreSQL or Kafka for the whole test job
  • local developer machines with stable tooling
  • CI pipelines where startup cost matters more than isolation

The tradeoff is weaker test isolation than Testcontainers.

Alternative 3: KinD or k3d for Kubernetes-Focused Tests

If the real goal is Kubernetes behavior, run a lightweight local cluster such as KinD or k3d in CI:

bash
1kind create cluster --name spring-it
2kubectl apply -f k8s/
3kubectl rollout status deployment/my-app
4kubectl get pods

Then execute smoke or end-to-end checks against the deployed service. This validates manifests, probes, services, and config wiring in a way Testcontainers does not.

This is a better choice than forcing application integration tests to pretend they are cluster tests.

Alternative 4: Ephemeral Namespaces in a Shared Cluster

For larger teams, a shared non-production cluster with namespace-per-build can be more realistic than local cluster tooling. CI creates a short-lived namespace, deploys the chart, runs tests, then deletes the namespace.

That approach is useful when you need:

  • a real ingress controller
  • cloud-managed storage classes
  • admission policies
  • service mesh or network policy behavior

It costs more operationally, but it covers the platform details that local containers cannot reproduce.

A Good Spring Test Pattern Without Testcontainers

Whatever infrastructure choice you make, keep Spring configuration explicit. One common pattern is to inject service endpoints via test properties:

java
1@SpringBootTest(properties = {
2    "spring.datasource.url=jdbc:postgresql://localhost:5432/app",
3    "spring.datasource.username=app",
4    "spring.datasource.password=secret"
5})
6class RepositoryIntegrationTest {
7
8    @Autowired
9    private UserRepository repository;
10
11    @Test
12    void savesUser() {
13        User user = repository.save(new User("Grace"));
14        assertNotNull(user.getId());
15    }
16}

That test works whether the database comes from Docker Compose, a local install, or a Kubernetes port-forward.

Choosing Between the Options

Pick the cheapest environment that still validates the risk you care about.

  • For repository logic, prefer embedded or local dependencies.
  • For realistic service integration, Docker Compose is often enough.
  • For manifest and cluster behavior, use KinD, k3d, or an ephemeral namespace in a real cluster.

Testcontainers is good because it collapses setup friction, but it should not decide the testing architecture by itself.

Common Pitfalls

The most common mistake is using Kubernetes for tests that only need a database connection. That makes the suite slower and harder to debug without increasing confidence very much.

Another mistake is treating Docker Compose as fully isolated. Shared services across tests can leak state, so data cleanup becomes your responsibility.

A third mistake is calling something an integration test when it is actually a deployment test. The tooling and success criteria are different.

Summary

  • Testcontainers is one option, not the architecture itself.
  • Use embedded or stubbed dependencies for fast application-level integration tests.
  • Use Docker Compose when you need real services but not a cluster.
  • Use KinD, k3d, or ephemeral namespaces when the goal is Kubernetes behavior.
  • Match the test environment to the risk being validated, not to habit.

Course illustration
Course illustration

All Rights Reserved.