
You're building a FHIR integration. You need to test it against data that looks like what a hospital actually produces.
You don't have access to a hospital.
This is the catch-22 that every FHIR startup lives in for 6-12 months. You can't get production EHR access without a working, tested integration. You can't build one without production-quality data. Epic's app marketplace review takes 2-4 months. Oracle Health takes 3-6. And all of them want evidence that your software works before they give you the data to prove it.
The Testing Pyramid for FHIR
Tier 1: Parse and Validate
Does your FHIR output conform to US Core profiles? You don't need a server for this. The HAPI FHIR Validator runs locally:
java -jar validator_cli.jar patient-bundle.json \
-ig hl7.fhir.us.core#6.1.0 \
-profile http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient
Run this in CI on every commit. It catches malformed resources, missing required fields, and profile violations.
Tier 2: Integration
This requires a running FHIR server with SMART on FHIR auth. You need to test the full request lifecycle: discovery, authorization, token exchange, scoped queries.
Things that break at this tier and nowhere else:
- Your search uses
Observation?category=laboratorybut the server indexes it asObservation?category=http://terminology.hl7.org/CodeSystem/observation-category|laboratory - Your SMART scopes request
patient/Observation.readbut the server only grantspatient/Observation.rs— read and search are separate grants -
Patient/$everythingreturns 2,000 entries with pagination links your client doesn't follow
Tier 3: Realistic
This is the tier most teams skip. You need patients that look like real patients:
| What you're testing | What the data needs |
|---|---|
| Lab trending UI | 3+ years of longitudinal labs with reference ranges |
| Medication reconciliation | 8-12 active medications with start dates and dosages |
| Problem list display | 5-15 active conditions with SNOMED coding |
| Prior auth workflow | Complex patients who actually get denied |
If your Tier 3 data is a single patient named "Test Cancer" with one condition, your tests aren't testing anything.
Your Options
Option 1: Local HAPI + Synthea
You've probably already done this. HAPI in Docker, a handful of Synthea patients, maybe a script that generates 10 bundles.
docker run -p 8080:8080 hapiproject/hapi:latest
cd synthea && ./run_synthea -p 10
When this is enough: Early prototyping, Tier 1 validation.
When it isn't: No SMART auth. Synthea defaults produce patients with single conditions and no clinical depth. At some point the test data pipeline becomes its own project — one you maintain alongside the product you're actually building.
Option 2: Vendor Sandboxes
Open Epic, Oracle Health Code, SMART Health IT Sandbox.
When this is enough: Testing OAuth against a real vendor's auth server.
When it isn't: Open Epic gives you 8 patients with sparse data. No comorbidity patterns. No longitudinal labs. No imaging. No clinical notes. We wrote a whole post about this.
Option 3: Clinically Realistic Sandbox
A FHIR server with SMART auth and patients generated from real clinical patterns.
curl -s https://api.mock.health/fhir/Condition?patient=example \
-H "Authorization: Bearer $TOKEN" | jq '.entry[].resource.code.coding[0].display'
"Type 2 diabetes mellitus"
"Essential hypertension"
"Chronic kidney disease, stage 3"
"Hyperlipidemia"
"Diabetic retinopathy"
These conditions travel together because the generation engine learned that pattern from real CMS claims data. Compare to Open Epic: "Pain in throat".
What Changes When You Get Production Access
Your sandbox-tested code won't ship unmodified. You'll encounter vendor-specific extensions, data quality variance (plan for trash), and an opaque app review process.
But the architecture you built against a sandbox will survive. The specific data handling will need adaptation. That's normal — sandbox testing builds the 90% that doesn't depend on vendor-specific behavior.
| Tier | Tool | Catches |
|---|---|---|
| 1 | HAPI Validator in CI | Malformed resources, profile violations |
| 2 | SMART-enabled sandbox | OAuth bugs, search parameter issues |
| 3 | Realistic synthetic data | Logic errors with complex patients |
Run Tier 1 on every commit. Run Tier 2 when you change auth or query logic. Run Tier 3 before every demo and before you apply for production access.
mock.health — SMART-enabled FHIR sandbox with clinical density to get through Tier 3 testing. API key in 60 seconds →
Top comments (0)