Skip to content

TestPlan Dependencies

Managing test execution order and dependencies in TestPlans.

Dependency Resolution

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:

Circular dependency detected: TestPlan/plan-a -> TestPlan/plan-b -> TestPlan/plan-a

Dependency Resolution

Algorithm

  1. Build dependency graph
  2. Detect cycles
  3. Topological sort
  4. 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:

Test A: PASS
Test B (depends on A): PASS
Test C (depends on B): FAIL
Test D (depends on C): 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() {}
}

Next Steps