Testing & Debugging
Debug locally in IntelliJ IDEA or Eclipse and validate workflows with representative HL7 inputs.
The SDK is designed for fast local feedback: run representative HL7 inputs under a debugger, inspect the parsed message and generated FHIR Bundle, then turn important scenarios into repeatable automated tests.
Local Bundle debugging
- Configure
config/sdk.properties. - Place a representative HL7 message under
input/. - Set breakpoints in
shouldProcess,preConvert,postConvert, or reusable workflow classes. - Run the SDK launcher in debug mode.
- Inspect the current
MessageEnvelope, parsed HAPI HL7 message, and generated FHIR resources. - Review the generated
output/bundle.json.
Useful debugger values include messageCode, triggerEvent, messageControlId, the parsed HAPI HL7 object, and the generated FHIR Bundle. This makes it easy to compare the original HL7 input with the exact resources produced by the workflow.
IDE workflows
Eclipse debugging
- Open the SDK launcher class.
- Choose Debug As → Java Application.
- Set breakpoints in
Main.groovy, lifecycle hooks, or reusable workflow classes. - Run a representative HL7 input and inspect
MessageEnvelope, HAPI HL7 objects, and generated FHIR resources. - Review
output/bundle.jsonafter execution.
IntelliJ IDEA debugging
- Create or select the SDK launcher Run/Debug configuration.
- Set breakpoints in
Main.groovy, lifecycle hooks, or workflow classes. - Choose Debug and run a representative HL7 input.
- Inspect
MessageEnvelope, HAPI HL7 objects, and the generated FHIR Bundle. - Review
output/bundle.jsonafter execution.
Debugging with FHIR server delivery
Local Bundle output is the safest default for development. When the integration must be exercised against a development FHIR server, switch the SDK output mode and configure the endpoint:
sdk.output.mode=fhirserver
fhir.server.url=http://localhost:8080/fhir
In this mode the SDK transforms the representative HL7 input and sends the generated FHIR Bundle to the configured development endpoint, allowing the complete script-and-delivery path to be debugged.
Do not point local SDK debugging at a production FHIR server. Use an isolated development or test endpoint with representative test data.
Included test examples
The Developer SDK includes example Spock tests and reusable test helpers under src/test/groovy/. They provide a starting point for testing lifecycle hooks, semantic rules, HL7/FHIR scenarios, and project-specific regression cases.
src/test/groovy/
├─ MainSpec.groovy
├─ core/
│ ├─ EncounterRulesSpec.groovy
│ └─ PatientRulesSpec.groovy
└─ support/
├─ EncounterBuilder.groovy
├─ MessageEnvelopeBuilder.groovy
├─ PatientBuilder.groovy
├─ SemanticRuleTestKit.groovy
└─ TestFixtures.groovy
The supplied tests demonstrate lifecycle-hook testing, semantic-rule testing, reusable fixtures, and helper builders for repeatable interoperability scenarios.
Run the test suite
From the SDK project root, run:
mvn clean test
This compiles the project and executes the included Spock/JUnit test suite. Add your own regression tests under src/test/groovy/ alongside the supplied examples.
Automated testing strategy
A practical SDK project normally uses three testing levels:
| Level | Best for | Typical approach |
|---|---|---|
| Unit tests | Hooks, helpers, normalizers, workflow classes | Call Groovy methods directly with in-memory test fixtures. |
| Semantic-rule tests | Business and interoperability validation rules | Load the real rule and validate an in-memory FHIR Bundle. |
| SDK integration tests | Representative HL7 → FHIR behavior | Run HL7 samples through the SDK and assert the generated FHIR output. |
Unit testing workflow hooks with Spock
Lifecycle hooks are ordinary methods and can be tested directly without starting FireSonic or a FHIR server.
class MainSpec extends Specification {
def "shouldProcess accepts message by default"() {
given:
def script = new Main()
def envelope = envelope().build()
when:
FilterResult result = script.shouldProcess(envelope)
then:
result.isAccepted()
}
def "postConvert returns bundle unchanged"() {
given:
def script = new Main()
def envelope = envelope().build()
def bundle = bundleOf(
patient().build(),
encounter().build()
)
when:
Bundle result = script.postConvert(envelope, bundle)
then:
result.is(bundle)
}
}
Testing semantic rules
Semantic rules can be tested independently with an in-memory Bundle. The example below verifies the complete diagnostic payload, not only whether a failure occurred.
def "patient without identifier creates one identifier issue"() {
given:
Patient patient = patient()
.setId("Patient/p1")
.setName("Emma", "Miller")
.withoutIdentifier()
.build()
when:
def issues = rules.validate(
"SEMANTIC-CORE-PAT-001",
bundleOf(patient)
)
then:
issues.size() == 1
and:
def issue = issues.first()
issue.ruleId == "SEMANTIC-CORE-PAT-001"
issue.severity.toString() == "ERROR"
issue.message == "Patient does not contain an identifier"
issue.resourceType == "Patient"
issue.resourceId == "Patient/p1"
}
Data-driven Spock tests
Spock's where: tables are well suited to mapping and validation boundary cases where the same behavior must be checked against several input combinations.
@Unroll
def "patient name is invalid when #caseName"() {
...
where:
caseName | givenName | familyName
"given name is missing" | null | "Miller"
"given name is blank" | " " | "Miller"
"family name is missing" | "Emma" | null
"family name is blank" | "Emma" | " "
"both names are missing" | null | null
}
Reusable test fixtures
Keep tests readable by centralizing repetitive FHIR and HL7 test-data construction in project test helpers. For example:
Patient patient = patient()
.setId("Patient/p1")
.withoutIdentifier()
.build()
Encounter encounter = encounter()
.setIdentifier("urn:test:encounter", "VN-1001")
.build()
Bundle bundle = bundleOf(patient, encounter)
A project test fixture can also load representative HL7 files from src/test/resources:
MessageEnvelope envelope = envelope()
.fromResource("hl7/adt-a01-with-multiple-al1.hl7")
.build()
Store realistic HL7 samples under test resources and include edge cases that have occurred in real integrations. This turns production knowledge into repeatable regression coverage.
SDK integration tests
For end-to-end SDK tests, use representative HL7 files as input, run them through the local SDK processing path, and assert the generated FHIR Bundle or expected failure. This is the right level for verifying interaction between message normalization, conversion, script hooks, and semantic validation.
Keep external dependencies controlled: prefer local fixtures and mock/test endpoints unless the purpose of the test is specifically to verify integration with a development FHIR or REST service.
