This application is not supported by InterSystems Corporation. Please be notified that you use it at your own responsibility.

What's new in this version

Initial Release


HL7 DTL TestCase Creator and Runner Framework

The mission of DTL UnitTest:

  • Write Tests faster
  • Confirm existing behavior is not broken by subsequent enhancements to Schema and or Transform
  • Allow future enhancements to proceed confidently without having to manually retest for breaking dependency changes.
  • Encapsualte referencable testable requirements for Transform behavior.
  • Stop losing sleep over deploying change and avoid unforseen impacts.
  • Retest fast and optionaly with continious integration
  • Provide tangible quality assurance via Test Output reports.

Each UnitTest is generated from discovered Transforms in the namespace. A UnitTest consists of:

  • one or more pairs of:
    • Source Message
    • Target Message (Expected)
  • A generated comparison method

At run time, for each pair of Source and Target message.

  • Load Source message
  • Transforms generate Actual output
  • Compare Actual output is compatible with Target (Expected)

How to use

The following will describe how to quickly get started with testing existing HL7 to HL7 Transforms.
Note the framework can also process:

  • Object to HL7 Message
  • Object to HL7 Segment
  • HL7 message to HL7 Segment
  • HL7 Segment to HL7 Message

Step 1 - Import class "UnitTest.DTL.HL7TestCase" into target namespace

Step 2 - Generate new TestCase(s)

This method analyses the namespace for matching DTL implemented classes.
For each DTL found, a new TestCase is created when one doesn't already exists. (Existing classes will not be overwritten).


Do ##class(UnitTest.DTL.HL7TestCase).GenerateTestCases("UnitTest.DTL.TestTrans.","UnitTest.Test.DTL.TestTrans.",0,,0,1,.pStatus)


  • matchPackage - The facility will search for any transform classes that match this package path
  • targetPackage - The base target package to generate new TestCase classes in. (Use different from source package).
  • copySubPackageNames - If enabled generate TestCase classes in sub packages as discovered from matched transforms
  • addToProject - If specified. Attempt to automatically add classes to the named Studio Package. (Running in Studio Output window).
  • listOnly - If enabled only list the classes that would be generated
  • pStatus - List of errors encountered.

Example variations:

// List Only Test, match ending in dot
Do ##class(UnitTest.DTL.HL7TestCase).GenerateTestCases("MEXX.Radiology.dtl.","MEXX.Radiology.test.dtl",1,,1,1,.pStatus)
// List Only match not ending in dot
Do ##class(UnitTest.DTL.HL7TestCase).GenerateTestCases("MEXX.Radiology.dtl","MEXX.Radiology.test.dtl",1,,1,1,.pStatus)
// List Only, No copy sub packages, match ending in dot
Do ##class(UnitTest.DTL.HL7TestCase).GenerateTestCases("MEXX.Radiology.dtl.","MEXX.Radiology.test.dtl",0,,1,1,.pStatus)
// List Only, No copy sub packages, match not ending in dot
Do ##class(UnitTest.DTL.HL7TestCase).GenerateTestCases("MEXX.Radiology.dtl","MEXX.Radiology.test.dtl",0,,1,1,.pStatus)
// Actually generate TestCases
// match ending in dot, follow sub package name convention
Do ##class(UnitTest.DTL.HL7TestCase).GenerateTestCases("MEXX.Radiology.dtl.","MEXX.Radiology.test.dtl",1,,0,1,.pStatus)

Step 3 - Optional Adjust Compare expressions

The source and target schemas have been extracted from the analyzed DTL
The generated compare method compares Expected with Actual HL7 values.
Some DTL expressions like Incrementing Counters and Current Date of tranfrom are volatile for each message.

This is the Unique Selling Point of this UnitTest approach!!

To exclude unique transform differences simply comment out unwanted compare experessions as shown .

/// Class Generated on 2022-08-14 19:19:11 using TestCase Generator V
/// <!--
/// do ##class(UnitTest.Test.DTL.TestTrans.TransformSource2).Debug()
/// -->
Class UnitTest.Test.DTL.TestTrans.TransformSource2 Extends UnitTest.DTL.HL7TestCase [ ProcedureBlock ]

Parameter SourceSchema = "2.5:ADT_A01";

Parameter TargetSchema = "2.5:ADT_A01";

Parameter TransformClass = "UnitTest.DTL.TestTrans.TransformSource2";

Method Compare(expectedTarget As EnsLib.HL7.Message, actualTarget As EnsLib.HL7.Message, source As EnsLib.HL7.Message)
// Add your path assertions here. For example: //
do ..AssertPathEquals(expectedTarget,"MSH:SendingApplication.NamespaceID",actualTarget,"MSH:SendingApplication.NamespaceID")
do ..AssertPathEquals(expectedTarget,"MSH:SendingApplication.UniversalID",actualTarget,"MSH:SendingApplication.UniversalID")
do ..AssertPathEquals(expectedTarget,"MSH:SendingApplication.UniversalIDType",actualTarget,"MSH:SendingApplication.UniversalIDType")
do ..AssertPathEquals(expectedTarget,"MSH:SendingFacility.NamespaceID",actualTarget,"MSH:SendingFacility.NamespaceID")
//do ..AssertPathEquals(expectedTarget,"MSH:SendingFacility.UniversalID",actualTarget,"MSH:SendingFacility.UniversalID")
do ..AssertPathEquals(expectedTarget,"MSH:SendingFacility.UniversalIDType",actualTarget,"MSH:SendingFacility.UniversalIDType")
do ..AssertPathEquals(expectedTarget,"MSH:ReceivingApplication.NamespaceID",actualTarget,"MSH:ReceivingApplication.NamespaceID")
do ..AssertPathEquals(expectedTarget,"MSH:ReceivingApplication.UniversalID",actualTarget,"MSH:ReceivingApplication.UniversalID")
do ..AssertPathEquals(expectedTarget,"MSH:ReceivingApplication.UniversalIDType",actualTarget,"MSH:ReceivingApplication.UniversalIDType")
do ..AssertPathEquals(expectedTarget,"MSH:ReceivingFacility.NamespaceID",actualTarget,"MSH:ReceivingFacility.NamespaceID")
do ..AssertPathEquals(expectedTarget,"MSH:ReceivingFacility.UniversalID",actualTarget,"MSH:ReceivingFacility.UniversalID")
do ..AssertPathEquals(expectedTarget,"MSH:ReceivingFacility.UniversalIDType",actualTarget,"MSH:ReceivingFacility.UniversalIDType")
//do ..AssertPathEquals(expectedTarget,"MSH:DateTimeOfMessage.Time",actualTarget,"MSH:DateTimeOfMessage.Time")


XData TESTMessageSource
<!-- Your Source HL7 Message or Segment content goes here -->

XData TESTMessageTarget
<!-- Your Expected output for HL7 Message or Segment content goes here -->


Step 4 - Add Some Messages

For a single Test DTL Source message and Target expected output message, simply replace the provided message template above with HL7 message content.

XData TESTMessageSource

XData TESTMessageTarget

Additional Source and expected output messages can be added as datablocks. Simply use names starting with "TEST" and ending with Source or Target accordingly. The additional tests are automatically added to the unit test run.

For programatically adding new Source messages and optionally generated outputs see method AddTestFromMessageBody

set tSC=##class(UnitTest.Test.DTL.TestTrans.TransformSource2).AddTestFromMessageBody("EnsLib.HL7.Message",2790,1,.sourceXdataName,.targetXdataName)

Populate Test XData blocks with message content

  • source Classname - eg: EnsLib.HL7.Message
  • sourceId - Saved ObjectId
  • generateDTLResult - "1" = Yes, "0"= No
  • sourceXdataName - Optional ByRef for output review
  • targetXdataName - Optional ByRef for output review

Step 4 - Core UnitTest runner dependency

The generated TestCases have the TestSuite of "TestDTL".
In the namespace the global ^UnitTestRoot must point at a real local directory. For example:

zw ^UnitTestRoot

For a TestSuite of "TestDTL", this means a directory with name "TestDTL" is required to exist. For example:


This is more to do with a dependency of the core UnitTest framework.
The TestCase will alert you if the directory doesn't exist or a different TestSuite is used.

Parameter TestSuite = "MyOtherTestSuite";

Step 4 - Run the TestCase

This will generate output on the console, with either success of failure

do ##class(UnitTest.Test.DTL.TestTrans.TransformSource2).Debug()
      TestMessage failed
    UnitTest.Test.DTL.TestTrans.TransformSource2 failed
  Skipping deleting classes
  TestDTL failedUse the following URL to view the result:$NAMESPACE=DTL_TEST                                                                Some tests FAILED in suites:

Step 5 - Review the results

Drill down into results using the URL generated by Core UnitTest functionality above.

  • Where the source Transform uses an expression that is invalid for the source schema, this will be flagged by the UnitTest
    This helps trap breaking changes either in Schema or Transform maintenance.
    Assert Failed Unable To Access Property Path

  • Where each expected value from the input TestMethodTarget DTL did not match the Actual value produced in the tranform, this will be highlighted.
    Assert Failed ExpectedNotActual

  • Where the Source and Target(Expected) HL7 messages are not schema conforming
    Assert Failed OverrideSegmentValidation
    As the message suggests: The validation can be disabled in generated TestCase, to continue path validation regardless of segment structure.

Parameter RequireValidSegmentStructure = 0;
  • Unable to read the HL7 from Source and Target XData blocks
    Please check Source and Target messages were added to generated TestCase
    Assert Failed UnableToCorrelateHL7
AssertFail:Correlate Message TESTMessageSource->ERROR #5001: Unable to ImportFromString with classname_"UnitTest.Test.DTL.TestTrans.TransformSource2"_XData "TESTMessageSource" with Schema "2.5:ADT_A01" (failed)  <<==== **FAILED**   TestDTL:UnitTest.Test.DTL.TestTrans.TransformSource2:TestMessage                                LogMessage:Duration of execution: .005246 sec.
      TestMessage failed
    UnitTest.Test.DTL.TestTrans.TransformSource2 failed
  Skipping deleting classes
  TestDTL failed

Utility Methods


Use case: To check whether a test message is behaving as expected for a property path.

  • classname - The fully package qualified class name of the test class extending DTLUnitTestBase
  • xdataName - The full Name (including prefix and suffix) of an XData block containing an HL7 Message or Segment
  • schema - The message schema (eg: 2.4:ADT_A05) or segment schema (eg: 2.4:MSH)
  • args - Future use multidimensional parameter to extend behaviour
Set hl7=##class(UnitTest.DTL.HL7TestCase).CorrelateMessage("UnitTest.Test.DTL.TestTrans.TransformSource2","TESTMessageSource","2.5:ADT_A01",,.pStatus)
Write hl7.GetValueAt("MSH:SendingFacility.NamespaceID")


Bonus Features

Extending the available core UnitTest Assertions the generated DTL TestCase provides new capabilities:


Usecase to constrain the output of a transformation to a range of values. Usecase 1:
There is a side-effect when the first time a transform is run it has the first actual value.
The second time a transform is run it has the second actual value.
Subsequent transforms also have the second actual value.
It is better to be able to constrain by unit tests the two possible values than to not constrain these output values at all.
Usecase 2:
Recieve order update messages by the Hospital System from a Radiology System.
Validate the OrderStatus is constrained to a list of expected values.
Description of parameters:
pTarget - An instance of EnsLib.HL7.Message or EnsLib.HL7.Segment
pTargetPath - The virtual document path to extract test value from. eg: "MSH:9.2"
pList - An ObjectScript list containing a list of values for equality eg: $LISTBULID("AB","B","C")
Usage :

do ..AssertListContainsPath(actualTarget,"OBR:ResultStatus",$LB("F","K"))


Converse of the Assert function AssertListContainsPath.
Description of parameters:

  • pTarget - An instance of EnsLib.HL7.Message or EnsLib.HL7.Segment
  • pTargetPath - The virtual document path to extract test value from. eg: "MSH:9.2"
  • pList - An ObjectScript List containing a list of values for equality eg: $LISTBULID("AB","B","C")
    Usage :
do ..AssertListNotContainsPath(actualTarget,"OBR:ResultStatus",$LB("P","E"))


Extending Assert method to validate that for object references:

  • The expected value is not empty
  • The actual value after transformation is not empty
  • Both the expected value and the actual value match


Check counts of sub-elements in path resolve to equal length lists

  • Return 0 = ASSERT fail
  • Return 1 = ASSERT OK


Extending Assert method to validate that for virtual document path:

  • The expected value is not empty
  • The actual value after transformation is not empty
  • Both the expected value and the actual value match
0 (0)
Works with
InterSystems IRIS for HealthHealthShareEnsemble
Last updated