TestPlan Dependencies¶
Managing test execution order and dependencies in TestPlans.
Dependency Resolution¶
Why Dependencies?¶
Some tests must run in specific order:
- Setup before tests - Create test data first
- Sequential operations - Update requires create
- Cleanup after tests - Delete test data last
- Data dependencies - Test B needs data from Test A
Defining Dependencies¶
Simple Dependency¶
{
"testCase": [
{
"sequence": 1,
"testRun": [{
"narrative": "Create patient",
"script": {"reference": "TestScript/patient-create"}
}]
},
{
"sequence": 2,
"dependency": [{
"predecessor": "TestScript/patient-create"
}],
"testRun": [{
"narrative": "Read patient",
"script": {"reference": "TestScript/patient-read"}
}]
}
]
}
Multiple Dependencies¶
{
"testCase": [
{
"sequence": 1,
"testRun": [
{"script": {"reference": "TestScript/create-patient"}},
{"script": {"reference": "TestScript/create-practitioner"}}
]
},
{
"sequence": 2,
"dependency": [
{"predecessor": "TestScript/create-patient"},
{"predecessor": "TestScript/create-practitioner"}
],
"testRun": [{
"narrative": "Create observation referencing both",
"script": {"reference": "TestScript/create-observation"}
}]
}
]
}
Execution Order¶
Sequential Execution¶
Use sequence for ordered execution:
{
"testCase": [
{"sequence": 1, "testRun": [{"script": {"reference": "TestScript/setup"}}]},
{"sequence": 2, "testRun": [{"script": {"reference": "TestScript/test1"}}]},
{"sequence": 3, "testRun": [{"script": {"reference": "TestScript/test2"}}]},
{"sequence": 4, "testRun": [{"script": {"reference": "TestScript/cleanup"}}]}
]
}
Parallel Execution¶
Tests without dependencies run in parallel:
{
"testCase": [
{
"testRun": [
{"script": {"reference": "TestScript/patient-test"}},
{"script": {"reference": "TestScript/practitioner-test"}},
{"script": {"reference": "TestScript/organization-test"}}
]
}
]
}
Dependency Patterns¶
Setup-Test-Teardown¶
{
"testCase": [
{
"sequence": 1,
"testRun": [{
"narrative": "Setup test data",
"script": {"reference": "TestScript/setup"}
}]
},
{
"sequence": 2,
"dependency": [{"predecessor": "TestScript/setup"}],
"testRun": [
{"script": {"reference": "TestScript/test1"}},
{"script": {"reference": "TestScript/test2"}},
{"script": {"reference": "TestScript/test3"}}
]
},
{
"sequence": 3,
"dependency": [
{"predecessor": "TestScript/test1"},
{"predecessor": "TestScript/test2"},
{"predecessor": "TestScript/test3"}
],
"testRun": [{
"narrative": "Cleanup",
"script": {"reference": "TestScript/teardown"}
}]
}
]
}
CRUD Sequence¶
{
"testCase": [
{
"sequence": 1,
"testRun": [{"script": {"reference": "TestScript/create"}}]
},
{
"sequence": 2,
"dependency": [{"predecessor": "TestScript/create"}],
"testRun": [{"script": {"reference": "TestScript/read"}}]
},
{
"sequence": 3,
"dependency": [{"predecessor": "TestScript/read"}],
"testRun": [{"script": {"reference": "TestScript/update"}}]
},
{
"sequence": 4,
"dependency": [{"predecessor": "TestScript/update"}],
"testRun": [{"script": {"reference": "TestScript/delete"}}]
}
]
}
Hierarchical Tests¶
{
"testCase": [
{
"sequence": 1,
"testRun": [{
"narrative": "Core resource tests",
"script": {"reference": "TestPlan/core-resources"}
}]
},
{
"sequence": 2,
"dependency": [{"predecessor": "TestPlan/core-resources"}],
"testRun": [{
"narrative": "Extension tests",
"script": {"reference": "TestPlan/extensions"}
}]
}
]
}
Cycle Detection¶
FHIR Frog detects circular dependencies:
// This will fail!
{
"testCase": [
{
"testRun": [{"script": {"reference": "TestPlan/plan-a"}}],
"dependency": [{"predecessor": "TestPlan/plan-b"}]
}
]
}
// Where plan-b depends on plan-a
Error:
Dependency Resolution¶
Algorithm¶
- Build dependency graph
- Detect cycles
- Topological sort
- Execute in order
Example Resolution¶
Input:
Test A (no deps)
Test B (depends on A)
Test C (depends on A)
Test D (depends on B, C)
Resolution:
1. Test A
2. Test B, Test C (parallel)
3. Test D
Best Practices¶
Minimize Dependencies
Only add dependencies when truly required. Independent tests can run in parallel.
Avoid Chains
Long dependency chains slow execution. Group independent tests together.
Good: Minimal Dependencies¶
{
"testCase": [
{
"sequence": 1,
"testRun": [{"script": {"reference": "TestScript/setup"}}]
},
{
"sequence": 2,
"dependency": [{"predecessor": "TestScript/setup"}],
"testRun": [
{"script": {"reference": "TestScript/test1"}},
{"script": {"reference": "TestScript/test2"}},
{"script": {"reference": "TestScript/test3"}}
]
}
]
}
Avoid: Excessive Dependencies¶
{
"testCase": [
{"sequence": 1, "testRun": [{"script": {"reference": "TestScript/test1"}}]},
{"sequence": 2, "dependency": [{"predecessor": "TestScript/test1"}],
"testRun": [{"script": {"reference": "TestScript/test2"}}]},
{"sequence": 3, "dependency": [{"predecessor": "TestScript/test2"}],
"testRun": [{"script": {"reference": "TestScript/test3"}}]},
// Long chain - slow execution
]
}
Error Handling¶
Fail Fast¶
If a dependency fails, dependent tests are skipped:
Continue on Failure¶
Use separate test cases for independent tests:
{
"testCase": [
{
"testRun": [{"script": {"reference": "TestScript/test1"}}]
},
{
"testRun": [{"script": {"reference": "TestScript/test2"}}]
}
]
}
If test1 fails, test2 still runs.
JUnit Integration¶
Dependencies map to JUnit test order:
@TestPlan("TestPlan/with-dependencies")
class TestSuite {
// Generated tests respect dependency order
@Test
@Order(1)
void setup() {}
@Test
@Order(2)
void test1() {}
@Test
@Order(3)
void cleanup() {}
}