Best Practices - Smile CDR Documentation

Best Practices for Testing with SmileCdrContainer and SmileHarness

This document provides recommendations for effective testing with SmileCdrContainer and SmileHarness. Following these best practices will help you write more efficient, reliable, and maintainable tests.

Container Management

Reuse Containers When Possible Starting and stopping Docker containers is resource-intensive. When writing multiple tests that use the same container configuration, consider using a shared container instance:

@Testcontainers
class MyTestSuite {

// Shared container for all tests in this class
    @Container
    private static final SmileCdrContainer container = new SmileCdrContainer("2025.02.R02");

private static SmileHarness harness;

@BeforeAll
    static void setup() {
        harness = container.getHarness();
    }

@Test
    void test1() {
        // Use the shared container and harness
    }

@Test
    void test2() {
        // Use the same shared container and harness
    }
}

Copy

Note that since the SmileCdrContainer is defined as static, it will be reused through the entire test class. Important to note that any data stored by one test will be accessible by another. This may not be what you want, so it is important to consider which lifecycle to use. Use Appropriate Container Lifecycle Consider the appropriate lifecycle for your container:

Choose based on whether your tests need isolation or can share state. Set Appropriate Timeouts Docker containers can take time to start, especially for complex applications like Smile CDR. Set appropriate timeouts to avoid test failures due to slow startup:

SmileCdrContainer container = new SmileCdrContainer("2025.02.R02")
    .withStartupTimeout(Duration.ofMinutes(5));

Copy

Test Design

Write Focused Tests Each test should focus on testing a specific functionality:

@Test
void testPatientCreation() {
    // Test only patient creation
}

@Test
void testPatientSearch() {
    // Test only patient search
}

Copy

Avoid writing tests that try to test too many things at once, as they become difficult to maintain and debug. Use Descriptive Test Names Use descriptive names for your tests that clearly indicate what is being tested:

@Test
void testCreatePatientWithMultipleIdentifiers() {
    // Test creating a patient with multiple identifiers
}

Copy

Use Test Data Helpers Create helper methods or classes for generating test data to make your tests more readable and maintainable:

private Patient createTestPatient() {
    Patient patient = new Patient();
    patient.addName().setFamily("Test").addGiven("Patient");
    patient.setGender(Enumerations.AdministrativeGender.MALE);
    return patient;
}

Copy

Client Usage

Reuse Clients Create clients once and reuse them throughout your tests to avoid unnecessary overhead:

private static IGenericClient fhirClient;
private static AdminJsonRestClient adminClient;

@BeforeAll
static void setup() {
    harness = container.getHarness();
    fhirClient = harness.getSuperuserFhirClient();
    adminClient = harness.getAdminJsonClient();
}

Copy

Use Appropriate Authentication Use the appropriate level of authentication for your tests:

Configuration Management

Use Custom Properties Files For tests that require specific configurations, use custom properties files:

SmileCdrContainer container = new SmileCdrContainer()
    .withPropertiesFile("custom-config.properties");

Copy

This allows you to tailor the Smile CDR configuration to your specific test needs.

Performance Considerations

Minimize Container Restarts Starting and stopping containers is expensive. Design your tests to minimize container restarts:

Use Parallel Test Execution Carefully Testcontainers supports parallel test execution, but be careful with resource usage:

Consider Resource Requirements Smile CDR can be resource-intensive. Make sure your test environment has sufficient resources:

Debugging

Enable Remote Debugging For complex debugging scenarios where you want to add breakpoints to your own custom interceptor code, you can enable remote debugging on the container using withDebugEnabled():

SmileCdrContainer container = new SmileCdrContainer("2025.02.R02")
    .withPropertiesFile("my-config.properties")
    .withDebugEnabled();

Copy

This allows you to:

The container will pause during startup until you attach a debugger (default behavior). If you want the container to start without waiting for the debugger, use:

SmileCdrContainer container = new SmileCdrContainer("2025.02.R02")
    .withDebugEnabled(false);  // Don't suspend until debugger attaches

Copy

See the Enabling Remote Debugging section in the Usage guide for detailed instructions on connecting your debugger.

Inspect Container State Use the Testcontainers API to inspect the container state:

// Get container logs
String logs = container.getLogs();

// Execute a command in the container
ExecResult result = container.execInContainer("ls", "-la");

Copy

Advanced Techniques

Custom Wait Strategies By default, SmileCdrContainer is considered started when the "You are up and running" log message arrives in the logs. However, you can use custom wait strategies to ensure the container is fully ready before tests, if you have some alternate start conditions.

SmileCdrContainer container = new SmileCdrContainer("2025.02.R02")
    .waitingFor(Wait.forHttp("/Patient")
        .forPort(8000)
        .withBasicCredentials("admin", "password")
        .forStatusCode(200));

Copy

Conclusion

By following these best practices, you can write more effective tests with SmileCdrContainer and SmileHarness. Remember that good tests are:

Clients

Best Practices

Testing Tools

Overview Usage Clients Best Practices