CQL Testing Framework tests are written as files in the YAML format. If you are not familiar with YAML, you may find the YAML Cheat Sheet helpful as you review this documentation or write YAML test cases.
Each YAML file in the tests
folder is a separate test case. Each file has the following general components:
- name: The name of the test case.
- externalData: A YAML array of the names of other YAML files which may contain anchored resource definitions which can be referenced below under the
data
section. See "Reusing Resources" below for more information. - data: A sequence (i.e., array) of the resource instances making up the test case (with the
Patient
resource as the first one). Can include YAML references to anchored resources defined in any YAML files listed under theexternalData
section. - results: A hash (i.e. object) for which each key corresponds to a CQL expression name and the value is the expected result for that CQL expression.
The following is a very simple example of a test case for a fictional CQL library with inclusion criteria that the patient must be male, over 18, and have an Opiod prescription on record. It sets up test data for a 40 year-old male with an Oxycodone prescription and specifies that the MeetsInclusionCriteria
CQL expression should evaluate to true
.
---
name: Meets Inclusion Criteria (40 y.o. male w/ Oxycodone)
data:
-
resourceType: Patient
name: Joe Smith
gender: male
birthDate: 1978-07-16
-
resourceType: MedicationOrder
code: RXNORM#1049599 12 HR Oxycodone Hydrochloride 80 MG Extended Release Oral Tablet
dateWritten: 2018-12-05
results:
MeetsInclusionCriteria: true
The data
section of the YAML file contains all of the data that will be associated to the patient record that the CQL will be run against. This data is represented as a sequence (array) of objects in YAML. Each object has a resourceType
indicating its FHIR type. Other attributes on the object are specific to the FHIR resource type.
The CQL Testing framework now supports all FHIR DSTU2, STU3, and R4 resource types. It provides this support by dynamically referencing the formal FHIR definitions of each resource, ensuring that specified fields in the YAML file are valid fields for that resource.
The CQL Testing Framework assigns default patient references and some default values, as well as user-friendly aliases (where applicable). For detailed information about each supported resource, its defaults, and its aliases, see the detailed documentation linked below:
FHIR DSTU2 Resources Documentation
FHIR STU3 Resources Documentation
FHIR R4 Resources Documentation
When constructing YAML test cases, standard types (such as string
, boolean
, integer
) are represented via the noraml YAML representations of those types. The CQL Testing Framework, however, also provides advanced support for the following other common FHIR data types: Quantity
, date
, dateTime
, Period
, CodeableConcept
, Coding
, id
, Reference
, HumanName
, and arbitrary complex types. Further details on each type are below.
A quantity of measurement with or without units specified. If units are specified, then they should be valid UCUM units.
Examples:
8
8.5
130 mg/dL
130.5 mg/dL
A string having the format: yyyy-MM-dd
.
Examples:
2018-11-05
A string formatted as an ISO 8601 compliant datetime.
Examples:
2008-11-12T16:00:00.000
2008-11-12T16:00:00.000Z
2008-11-12T16:00:00.000+00:00
A start datetime and end datetime separated by -
. If only one datetime is supplied, it is considered to be the start datetime.
Examples:
2008-11-12T16:00:00.000 - 2008-11-12T17:00:00.000
2008-11-12T16:00:00.000Z - 2008-11-12T17:00:00.000Z
2008-11-12T16:00:00.000
A string with the format: SYSTEM#code Optional Display Text
. The following system abbreviations are supported:
Abbreviation | URI |
---|---|
SNOMED, SNOMEDCT, SNOMED-CT, SCT | http://snomed.info/sct |
LOINC | http://loinc.org |
RXNORM, RXN, RX | http://www.nlm.nih.gov/research/umls/rxnorm |
UCUM | http://unitsofmeasure.org |
CPT | http://www.ama-assn.org/go/cpt |
CVX | http://hl7.org/fhir/sid/cvx |
ICD-10, ICD10 | http://hl7.org/fhir/sid/icd-10 |
ICD-10-CM, ICD10CM | http://hl7.org/fhir/sid/icd-10-cm |
ICD-10-PCS, ICD10PCS | http://www.icd10data.com/icd10pcs |
ICD-9, ICD9, ICD-9-CM, ICD9CM | http://hl7.org/fhir/sid/icd-9-cm |
ICD-9-D, ICD9D, ICD-9-CM-D, ICD9CMD * | http://hl7.org/fhir/sid/icd-9-cm |
ICD-9-P, ICD9P, ICD-9-CM-P, ICD9CMP * | http://hl7.org/fhir/sid/icd-9-cm |
OBS-CAT, OBSCAT | http://hl7.org/fhir/observation-category |
V3-ROLE-CODE | http://hl7.org/fhir/v3/RoleCode |
V3-RACE | http://hl7.org/fhir/v3/Race |
V3-ETHNICITY | http://hl7.org/fhir/v3/Ethnicity |
* The specific ICD-9 diagnosis and procedure aliases are supported for backwards-compatibility, but have been updated to resolve to the standard ICD-9 URL. FHIR removed the diagnosis/procedure-specific URLs from the specification, as they were deemed inappropriate for use.
In addition, URIs can be used directly as the system.
Examples:
RXNORM#198440 Acetaminophen 500 MG Oral Tablet
SNOMED#203082005 Fibromyalgia (disorder)
http://custom-system.org/codes#12345 Example Custom Code
A string identifier. If none is provided for a data instance, it will default to a randomly generated UUIDv4 string.
Examples:
2142fd65-893d-45f8-a2a3-ca9bae7f5dbc
547
patient-1
A string identifier for a reference to another instance. May contain just the id, the type and id, or a full URL.
Examples:
2142fd65-893d-45f8-a2a3-ca9bae7f5dbc
Patient/547
http://example.org/fhir/Patient/patient-1
A human name. If only one word is provided, it is assumed to be the first name. If more than one word is provided, only the last word is considered to be the last name.
Examples:
Sally
Sally Jones
Sally Jane Jones
A type that is a complex structure, i.e., has nested attributes and values. These types are supported via the normal YAML mechanism of indenting nested attribute/value pairs.
Example of specifying two Observation components (note: this demonstrates array notation as well):
component:
-
code: LOINC#8480-6 Systolic Blood Pressure
valueQuantity: 109 mm[Hg]
-
code: LOINC#8462-4 Diastolic Blood Pressure
valueQuantity: 44 mm[Hg]
The results
section contains the expected results when the data is run against the CQL logic. For each key specified in the results
section, the CQL Testing Framework will compare its value to the actual value of the CQL expression of the same name. Any CQL expressions without corresponding keys in the results
section are not checked. This allows test authors to check the expressions they care about but ignore others (which are often just intermediate expressions anyway).
The following is an example of a results
section:
results:
MeetsInclusionCriteria: false
Recommendation: null
The above results
section indicates that the CQL expression named MeetsInclusionCriteria
should evaluate to false
, and the cql expression named Recommendation
should evaluate to null
. If the actual CQL results were different than these expected values, the test would fail.
Nested structures are allowed. For example, the following is valid (assuming it matches the structure of the returned CQL expression types):
results:
PatientDetails:
Age: 40
IsMale: true
Recommendation: Do it!
_NOTE: When comparing expected results, the CQL Testing Framework converts CQL Dates and DateTimes to strings before comparing. For this reason, you must specify any expected dates or datetime results as strings, delimited with single quotes (e.g., '2017-11-15T16:00:00.000+00:00'
).
Aside from directly specifying the expected value of expressions output by the CQL, tests results can also verify certain output expression properties. This is done by the special $should
expression, as shown in the following example:
results:
# To check for strict equality, simply list desired output objects under `results`.
FirstCqlExpression:
...
# Can also verify certain output object properties by using `$should` expressions.
# The following indicates that the SecondCqlExpression object should exist.
SecondCqlExpression: $should exist
# The following indicates that these outputs should be arrays of length 1
ThirdCqlExpression: $should have length 1
FourthCqlExpression: $should have length 1
Currently only the exist
and have length
methods are supported.
As mentioned earlier, resources can be defined in separate YAML files (using the same format as described above) and then referenced in named test cases. Reusable resources must be marked using YAML anchor (&
) indicators and then referenced using YAML alias (*
) indicators.
There are two methods that are currently supported for resource reuse:
$import
: Imports all resources included within the referenced anchor into the current test case.$iterate
: Creates a set of test cases, each containing just one of the resources within the referenced anchor. If the referenced anchor containsN
resources,N
different test cases will be created, each of which will also contain any other resources listed in the main test case file. If there are multiple$iterate
methods, a test case will be generated for every possible combination of them. For example, if there are two$iterate
methods and the first containsM
resources and the second containsN
resources, this will result inM x N
test cases.
Consider some resources stored in a plain YAML file named reusable_resources.yml
:
# This key should be unique, but otherwise can be named anything that is valid YAML.
reusable_resources:
# Note use of anchor (&) indicator that allows `painRelatedConditions` to be referenced elsewhere.
- &painRelatedConditions
- resourceType: Condition
code: SNOMED#203082005 Fibromyalgia (disorder)
onsetDateTime: 2012-04-05
- resourceType: Condition
code: SNOMED#191722009 Agoraphobia with panic attacks (disorder)
onsetDateTime: 2014-09-05
These resources can be referenced in a named test case YAML file as follows:
---
name: Example of using reusable resources from another file
# This tells `cql-testing` to import everything contained in `reusable_resources.yml`.
externalData:
- reusable_resources
data:
-
resourceType: Patient
name: Fuller Jackson
gender: male
birthDate: 1954-02-16
# Note use of alias (*) indicator to reference `painRelatedConditions`.
-
$import: *painRelatedConditions
See test\yaml\pain_dstu2\tests\
for more examples, including use of the $iterate
keyword.
Because they rely on the built-in YAML features of anchors and references, reusable resources can be placed in the main test case file instead of in a separate file. This can useful if there is a single or small handful of data elements that are being reused. The following example illustrates this capability.
In the following example the CQL library is expected to output three seperate expressions which should all include the same resources.
---
name: Example of using reusable resources from within the same file
# This key should be unique, but otherwise can be named anything that is valid YAML.
reusable_resources:
- &painRelatedConditions
- resourceType: Condition
code: SNOMED#203082005 Fibromyalgia (disorder)
onsetDateTime: 2012-04-05
- resourceType: Condition
code: SNOMED#191722009 Agoraphobia with panic attacks (disorder)
onsetDateTime: 2014-09-05
# In contrast with previous example, there are no external data files listed here.
data:
-
resourceType: Patient
name: Fuller Jackson
gender: male
birthDate: 1954-02-16
-
$import: *painRelatedConditions
# These three output expressions should contain the same results
results:
PainRelatedConditions: *painRelatedConditions
ConditionsRelatedToPain: *painRelatedConditions
AllConditions: *painRelatedConditions