Skip to content

Testcontainers Setup

Run FHIR tests against an automatically managed HAPI FHIR container. No manual server setup required.

Prerequisites

  • Docker installed and running
  • fhir-frog-test-fixtures on the test classpath

Add Testcontainers Dependency

pom.xml
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>junit-jupiter</artifactId>
    <scope>test</scope>
</dependency>

Standard HAPI Server

For tests against a plain FHIR R4 server with no IG:

@Testcontainers
@ExtendWith(FhirFrogExtension.class)
class PatientIT {

    @Container
    static GenericContainer<?> hapi = new GenericContainer<>("hapiproject/hapi:v7.6.0")
        .withExposedPorts(8080)
        .waitingFor(Wait.forHttp("/fhir/metadata").withStartupTimeout(Duration.ofMinutes(3)));

    @FhirTestConfig
    FhirTestConfig config() {
        return FhirTestConfig.builder()
            .serverUrl("http://localhost:" + hapi.getMappedPort(8080) + "/fhir")
            .fixtureBasePath(Path.of("src/test/resources/fhir"))
            .build();
    }

    @TestTemplate
    @TestScriptSource("fhir/patient-lifecycle.tsh")
    void patientLifecycle(FhirTestConfig config) { }
}

Pre-warmed IG Server (Bootstrap Pattern)

For IGs with large dependency trees (e.g. AU Core, AU eRequesting), a cold HAPI startup can take 10–20 minutes. Use the bootstrap pattern to create a pre-warmed Docker image once and reuse it:

# First time only: build the pre-warmed image
ant fetch-jar && ant init && ant bootstrap

Then in tests:

@Testcontainers
class AUCoreIT {

    @Container
    static GenericContainer<?> hapi = new GenericContainer<>("hapi-au-core:1.0.0")
        .withExposedPorts(8080)
        .waitingFor(Wait.forHttp("/fhir/metadata").withStartupTimeout(Duration.ofSeconds(60)));

    // ~25 seconds startup vs ~15 minutes cold
}

See Ant Task for the full bootstrap workflow.

Shared Container (Class-Level)

For performance, share one container across all tests in a class:

@Testcontainers
class PatientSuiteIT {

    @Container
    static final GenericContainer<?> HAPI =
        new GenericContainer<>("hapiproject/hapi:v7.6.0")
            .withExposedPorts(8080)
            .waitingFor(Wait.forHttp("/fhir/metadata")
                .withStartupTimeout(Duration.ofMinutes(3)));

    private FhirTestConfig config() {
        return FhirTestConfig.builder()
            .serverUrl("http://localhost:" + HAPI.getMappedPort(8080) + "/fhir")
            .build();
    }
}

static + @Container means the container starts once for the whole test class.

Tips

  • Use waitingFor(Wait.forHttp("/fhir/metadata")) — HAPI is ready when metadata responds
  • Increase withStartupTimeout for IGs with many packages
  • Use @Container static to avoid starting/stopping between tests
  • See bootstrap pattern for IG-heavy setups

Next Steps