This document provides examples and common usage patterns for working with SmileCdrContainer
and SmileHarness
in your tests.
The most common way to use SmileCdrContainer
is with JUnit 5's @Testcontainers
and @Container
annotations:
import ca.cdr.test.extensions.SmileCdrContainer;
import ca.cdr.test.app.harness.api.SmileHarness;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
@Testcontainers
class MyTest {
// Define the Docker tag to use
static String smilecdrVersion = "2025.02.R02";
// Create and configure the container
@Container
private static SmileCdrContainer container = new SmileCdrContainer(smilecdrVersion);
// Store the harness for use in tests
private static SmileHarness harness;
@BeforeAll
public static void setup() {
// Get the harness from the container
harness = container.getHarness();
}
@Test
public void testSomething() {
// Use the harness to interact with Smile CDR
}
}
You can specify which version of Smile CDR to use, which remote docker registry to use, and which tag to use:
// Using a default version of Smile CDR that the SmileCdrContainer selects.
SmileCdrContainer container = new SmileCdrContainer();
// Using the default registry with a specific Smile CDR version
SmileCdrContainer container = new SmileCdrContainer("2025.02.R02");
// Using a fully custom Docker registry, image, and tag. This can be useful if you have customized
// the base docker image and host it yourself.
DockerImageName customImage = DockerImageName.parse("my-registry.com/my-image:my-tag");
SmileCdrContainer container = new SmileCdrContainer(customImage);
You can provide a custom properties file to configure the Smile CDR instance:
SmileCdrContainer container = new SmileCdrContainer()
.withPropertiesFile("my-custom-config.properties");
The properties file must be available on the classpath. Please see the tutorial for examples.
By default, the SmileCdrContainer will assume several things to bootstrap connectivity to the Smile CDR container. Specifically it assumes:
If the configuration you are using does not match the above, you must provide the new information to the Harness Context before building a Smile Harness
You can provide a custom HarnessContext
to configure how the harness connects to Smile CDR:
String baseUrl = "http://localhost";
Integer adminJsonPort = 19000;
String adminUsername = "my-admin";
String adminPassword = "my-random-password";
HarnessContext context = new HarnessContext(baseUrl, adminJsonPort, adminUsername, adminPassword);
SmileCdrContainer container = new SmileCdrContainer("2025.02.R02")
.withCustomHarnessContext(context);
Once you have a SmileHarness
instance, you can use it to interact with the Smile CDR instance in various ways.
// Get a FHIR client
IGenericClient fhirClient = harness.getFhirClient();
// Add authentication if needed
BasicAuthInterceptor authInterceptor = new BasicAuthInterceptor("username", "password");
// Register the interceptor
fhirClient.registerInterceptor(authInterceptor);
// Use the client to interact with FHIR resources
Bundle bundle = fhirClient.search()
.forResource("Patient")
.returnBundle(Bundle.class)
.execute();
// Get an Admin JSON client
AdminJsonRestClient adminClient = harness.getAdminJsonClient();
// Use the client to interact with the Admin API
NodeConfigurations config = adminClient.getNodeConfigurations();
The HL7V2RestClient
allows you to send HL7v2 messages to Smile CDR and process the responses. There are several ways to obtain and use this client.
// Get an HL7v2 REST client using the default port (7000)
HL7V2RestClient hl7v2Client = harness.getHL7V2RestClient();
// Get an HL7v2 REST client for a specific port
HL7V2RestClient hl7v2ClientWithPort = harness.getHL7V2RestClient(7001);
// Get an HL7v2 REST client for a specific module ID
HL7V2RestClient hl7v2ClientWithModuleId = harness.getHL7V2RestClient("hl7_endpoint_two");
You can send an HL7v2 message as a raw string:
// Create a raw HL7v2 message as a string
String rawMessage = "MSH|^~\\&|TestApp|TestFacility|SmileCDR|SmileCDR|20230101120000||ADT^A01^ADT_A01|123456|P|2.5\r" +
"PID|||12345||Smith^John||19800101|M";
// Send the message to the server
Message response = hl7v2Client.sendMessage(rawMessage);
// Verify the response is an acknowledgment
assertThat(response.getName()).contains("ACK");
ADT (Admission, Discharge, Transfer) messages are commonly used in healthcare systems. Here's how to create and send an ADT_A01 message:
// Create a sample ADT_A01 (admission) message
ADT_A01 adt = new ADT_A01();
MSH msh = adt.getMSH();
// Set required MSH fields
msh.getFieldSeparator().setValue("|");
msh.getEncodingCharacters().setValue("^~\\&");
msh.getSendingApplication().getNamespaceID().setValue("TestApp");
msh.getSendingFacility().getNamespaceID().setValue("TestFacility");
msh.getReceivingApplication().getNamespaceID().setValue("SmileCDR");
msh.getReceivingFacility().getNamespaceID().setValue("SmileCDR");
msh.getDateTimeOfMessage().getTime().setValue("20230101120000");
msh.getMessageType().getMessageCode().setValue("ADT");
msh.getMessageType().getTriggerEvent().setValue("A01");
msh.getMessageType().getMessageStructure().setValue("ADT_A01");
msh.getMessageControlID().setValue("123456");
msh.getProcessingID().getProcessingID().setValue("P");
msh.getVersionID().getVersionID().setValue("2.5");
// Set patient information
adt.getPID().getPatientID().getIDNumber().setValue("12345");
adt.getPID().getPatientName(0).getFamilyName().getSurname().setValue("Smith");
adt.getPID().getPatientName(0).getGivenName().setValue("John");
adt.getPID().getDateTimeOfBirth().getTime().setValue("19800101");
adt.getPID().getAdministrativeSex().setValue("M");
// Send the message to the server
Message response = hl7v2Client.sendMessage(adt);
// Process the response
if (response.getName().contains("ACK")) {
// Handle acknowledgment
System.out.println("Message acknowledged");
} else {
// Handle other response types
System.out.println("Received response: " + response.getName());
}
Smile CDR provides a test data helper class that can generate sample HL7v2 messages for you:
// Get the FHIR context from the harness
FhirContext fhirContext = harness.getFhirContext();
// Create a test data helper
Hl7V2TestDataHelper testDataHelper = Hl7V2TestDataHelper.buildDefault(fhirContext);
// Create a sample ADT_A01 message using the helper
ADT_A01 adtA01 = testDataHelper.createAdtA01();
// Send the message to the server
Message response = hl7v2Client.sendMessage(adtA01);
The Hl7V2TestDataHelper
provides methods for creating various types of HL7v2 messages with realistic test data, saving you the effort of manually populating all the required fields.
// Get the FHIR context from the first found persistence module
FhirContext fhirContext = harness.getFhirContext();
// Get the FHIR context from a named persistence module
String persistenceModuleId = "my_persistence_r4_module";
FhirContext fhirContext = harness.getFhirContext(persistenceModuleId);
When working with Docker containers, port mapping is important to understand. The SmileCdrContainer
maps container ports to host ports, and the SmileHarness
handles this mapping for you:
// Get a FHIR client for a specific port
IGenericClient fhirClient = harness.getFhirClient(8000);
// The harness automatically maps the container port to the host port
String serverBase = fhirClient.getServerBase();
// serverBase will be something like "http://localhost:32789"
You can also get the port mapping directly from the container:
Integer mappedFhirPort = container.getMappedPort(8000);
If your Smile CDR instance has multiple modules of the same type (e.g., multiple FHIR endpoints), you can specify which one to use:
// Get a FHIR client for a specific module by ID
IGenericClient fhirClient = harness.getFhirClient("my_endpoint_module");
// Get a FHIR client for a specific module by port
IGenericClient fhirClient = harness.getFhirClient(8010);
// Get a FHIR context for a specific module by ID
FhirContext fhirContext = harness.getFhirContext("my_persistence_module");
For a step-by-step guide to writing tests with SmileCdrContainer
and SmileHarness
, see the tutorial.
For detailed information about the clients available through SmileHarness
, see Available Clients.
For recommendations on effective testing with SmileCdrContainer
and SmileHarness
, see Best Practices.