Article
· Nov 27 11m de lecture

Test de transformation des données

Le développement de la production interopérable InterSystems IRIS implique l'utilisation ou l'écriture de différents types de composants. Parmi ceux-ci figurent les services (qui traitent les données entrantes), les processus (qui gèrent le flux et la logique des données) et les opérations (qui gèrent les données ou les requêtes sortantes). Les messages circulant à travers ces composants doivent être constamment adaptés aux applications qui les utilisent. Ainsi, lesLes transformations de données constituent sans conteste le composant le plus courant dans les productions interopérables.

Au début du développement des transformations de données, l' outil de test du portail de gestion devient très utile. Il complète les tests programmatiques (tests unitaires), qui peuvent être mis en œuvre à un stade ultérieur pour éviter les régressions et garantir que les transformations continuent de fonctionner après l'application de modifications à l'environnement.

La première partie de cet article explique comment utiliser l'interface utilisateur de l'outil de test disponible dans Ensemble 2007 et ses versions ultérieures. Nous pouvons l'invoquer directement à partir de l'IDE Visual Studio Code avec n'importe quelle classe qui étend Ens.DataTransform.

Il convient de noter qu'une nouvelle interface utilisateur est désormais disponible pour l'éditeur DTL et l'outil de test. Dans la première partie de cet article, nous examinerons l'interface utilisateur actuelle (disponible dans Ensemble 2007 et les versions ultérieures). Dans la deuxième partie, en revanche, nous explorerons la nouvelle interface (disponible dans IRIS 2025.1 et les versions ultérieures).

La troisième ou dernière partie de cet article détaillera les tests unitaires des transformations de données. Elle présentera également quelques lignes directrices et bonnes pratiques pour le codage des transformations de données.

Première partie : Utilisation de l'interface utilisateur actuelle de l'outil de test

L'outil de test est accessible depuis Studio ou depuis le portail de gestion. Il est également possible de configurer une action serveur pour l'invoquer directement depuis VS Code.

Pour accéder à l'outil de test depuis le portail de gestion, accédez à Interopérabilité > Création > Transformation des données et ouvrez une transformation à l'aide du bouton 'Open' (ouvrir). La boîte de dialogue vous permettra de sélectionner uniquement les transformations DTL. Cependant, l'outil de test prend en charge toutes les classes qui étendent Ens.DataTransform ( voir plus loin).

   

L'URL de l'outil, lorsqu'il est invoqué à partir du portail de gestion, doit ressembler à ce qui suit:

http://localhost:58603/csp/healthshare/irisapp/EnsPortal.Dialog.TestTransform.zen?$ZEN_POPUP=1&$ZEN_SOFTMODAL=1&TRANSFORM=test.SampleTransformDTL

Examinons de plus près les différents composants de l'URL::

  • URL de base du serveur: il s'agit de l'URL de base de la passerelle IRIS CSP
  • Chemin d'accès au composant de test: il s'agit du chemin d'accès au composant de l'outil de test (zen)
  • Le reste de l'URL contient les valeurs des paramètres des composants:
    • $ZEN_POPUP: true (1) - cela signifie qu'il s'agit d'une fenêtre contextuelle
    • $ZEN_SOFTMODAL: true (1) - cela signifie que la fenêtre est modale
    • TRANSFORM: il s'agit du nom de la classe de transformation des données

Appel de l'outil depuis VS Code

 

À l'aide de l'URL du composant de test, vous pouvez appeler un outil depuis VS Code à l'aide d'une action serveur. Pour ce faire, ajoutez simplement un lien supplémentaire à la clé "links" d' objectscript.conn dans settings.json.

Pour IRIS for Health:

"objectscript.conn": {
       "links": {
         "Data Transform Test": "${serverUrl}/csp/healthshare/${namespace}/EnsPortal.Dialog.TestTransform.zen?$ZEN_POPUP=1&$ZEN_SOFTMODAL=0&TRANSFORM=${classname}"
       }
     }
 
Pour IRIS Data Platform:
"objectscript.conn": {
       "links": {
         "Data Transform Test": "${serverUrl}/csp/${namespace}/EnsPortal.Dialog.TestTransform.zen?$ZEN_POPUP=1&$ZEN_SOFTMODAL=0&TRANSFORM=${classname}"
       }
     }

 

Le lien utilise les variables suivantes exposées par l'extension ObjectScript:

  • ${serverUrl}: URL de base du serveur connecté.
  • ${namespace}: L'espace de noms connecté.
  • ${classname}: Le nom de la classe actuellement ouverte.

 

Pour plus d'informations sur la configuration des actions serveur, consultez Configuration et exécution d'actions serveur dans VS Code | Utilisation de Visual Studio Code comme environnement de développement pour les applications InterSystems | Composants et outils InterSystems.

Alors que la boîte de dialogue du portail vous permet de sélectionner uniquement des transformations DTL, l'outil de test prend en charge toutes les classes qui étendent Ens.DataTransform.

Pour les transformations DTL, cet outil récupère les classes source et cible à partir des attributs de l'élément DTL
. Pour les transformations non DTL (classes qui étendent Ens.DataTransform), l'outil utilise la signature de méthode Transform().

Lorsque la classe source et/ou cible est une classe de document virtuel (une classe qui étend Ens.VDoc.Interface), un type de document (DocType) est requis. Pour les transformations de données DTL, l'outil récupère les attributs de l'élément
, SourceDocType et TargetDocType. Pour les transformations non DTL, une implémentation de GetSourceDocType() et/ou GetTargetDocType() est obligatoire.

Exemple

Vous trouverez ci-dessous un exemple complet de transformation de données non DTL (étendant directement Ens.DataTransform) qui peut être utilisé avec l'outil de test. La transformation clone un message HL7 v2.3 SIU source et définit la valeur du composant de champ SCH:7.1 du message cible.

Class ut.ks.lib.interop.SampleTranform Extends Ens.DataTransform
{ 
ClassMethod Transform(source As EnsLib.HL7.Message, Output target As EnsLib.HL7.Message, aux As %String) As %Status
{
    #Dim sc as %Status
    #Dim ex as %Exception.AbstractException
    s sc = $$$OK
    try {
        s target = source.%ConstructClone(1)        
        s target.DocType = ..GetTargetDocType()
        d target.SetValueAt("hello","SCH:7.1")   
    } catch (ex) {
      s sc = ex.AsStatus()
    }
    return sc
}
 
ClassMethod GetSourceDocType() As %String
{
  return "2.3:SIU_S12"
}
 
ClassMethod GetTargetDocType() As %String
{
  return "2.3:SIU_S12"
}
 
}

 Jetez un coup d'œil à la petite vidéo ci-dessous pour voir comment ce code fonctionne:

 

Deuxième partie : Utilisation de l'outil de test avec la nouvelle interface utilisateur

À partir de la version 2025.1 d'InterSystems IRIS, l'éditeur DTL et l'outil de test disposent d'une nouvelle interface utilisateur alternative accessible depuis le portail de gestion ou l'IDE pour VSCode.

Pour accéder à la nouvelle interface utilisateur depuis le portail de gestion, accédez à Interopérabilité > Créer > Transformation des données et ouvrez une transformation à l'aide du bouton ‘open’. N'oubliez pas que la boîte de dialogue vous permet de sélectionner uniquement les transformations DTL. Pour passer à la nouvelle interface utilisateur, cliquez sur le bouton de nouvelle interface utilisateur "new UI". 
La nouvelle interface utilisateur est également accessible en tant qu'éditeur directement dans VS Code.

Contrairement à la version précédente, le nouvel outil de test prend uniquement en charge les transformations de données DTL. Pour l'utiliser avec une classe qui étend Ens.DataTransform, vous devez encapsuler l'appel à la méthode de classe Transform() dans une action de code. Consultez l'exemple suivant:

Class ut.ks.lib.interop.SampleTransformDTL Extends Ens.DataTransformDTL [ DependsOn = EnsLib.HL7.Message ]
{
 
Parameter IGNOREMISSINGSOURCE = 0;
Parameter REPORTERRORS = 0;
Parameter TREATEMPTYREPEATINGFIELDASNULL = 0;
Parameter GENERATEEMPTYSEGMENTS = 0;
XData DTL [ XMLNamespace = "http://www.intersystems.com/dtl" ]
{
<transform sourceClass='EnsLib.HL7.Message' targetClass='EnsLib.HL7.Message' sourceDocType='2.3:SIU_S12' targetDocType='2.3:SIU_S12' create='new' language='objectscript' >
<code>
<![CDATA[
    return ##class(ut.ks.lib.interop.SampleTranform).Transform(source,.target,.aux)
  ]]></code>
</transform>
}
}

 

Troisième partie: Tests programmatiques

Grâce au framework %UnitTest, il est facile d'écrire des tests programmatiques reproductibles et robustes pour les transformations de données. Pour en savoir plus, consultez l' excellent article de @Yuri Marx sur ce sujet et la documentation officielle.

En règle générale, il est recommandé que les transformations dépendent le moins possible des données contextuelles d'exécution autres que les objets source et auxiliaires.

D'une manière générale, il convient d'éviter toute opération autre que la source, la cible, les objets auxiliaires ou le contenu actuel de l'espace de noms. Vous trouverez ci-dessous quelques exemples des éléments à contourner:

  • En fonction de la production d'interopérabilité (par exemple, l'envoi d'une requête à une opération métier).
  • En présence d'une méthode de classe Transform() avec état.
  • Lors de l'exécution d'une entrée/sortie de fichier ou de base de données externe.

Si des données d'exécution supplémentaires sont nécessaires, la classe de transformation doit fournir des valeurs par défaut dans la mesure du possible. Pour ce faire, ajoutez des membres tels que des paramètres de classe ou des blocs XData à la classe de transformation.

Les paramètres peuvent contenir n'importe quelle valeur de chaîne (même multiligne) et, lorsqu'ils sont déclarés comme valeur de configuration, peuvent être modifiés dans un espace de noms donné après la compilation de la classe (un mécanisme de configuration appréciable, mais encore sous-estimé).

Les blocs XData sont plus adaptés aux petits documents XML, aux objets ou tableaux JSON, ou aux données structurées en texte. N'oubliez pas de considérer leslimites générales du système.

Les données plus volumineuses peuvent être mises à la disposition de la transformation à l'aide des éléments suivants:

Le paramètre auxiliaire “aux” est transmis par l'appelant de la méthode de classe Transform(). Il peut s'agir d'une valeur de type de données ou d'un OREF. Lorsque la transformation est utilisée dans l'action ‘send’ (envoyer) d'une règle de routage de messages, le routeur se transmet lui-même en tant que paramètre auxiliaire, et ses propriétés (par exemple, RuleActionUserData) deviennent disponibles pour la transformation.

Si la classe de transformation ne peut pas fournir les valeurs par défaut, le test doit les fournir et initialiser tout état requis avant d'exécuter la méthode Transform(). Si la transformation utilise, par exemple, un schéma HL7 personnalisé, celui-ci doit être chargé avant l'exécution du test. Le test doit, par exemple, effectuer les opérations suivantes:

  • importation des schémas HL7 personnalisés à l'aide de la méthode de classe EnsLib.HL7.SchemaXML.Import().
  • Importation des tables de recherche à l'aide de la méthode de classe Ens.Util.LookupTable.%Import().
  • Initialisation de toutes les autres données, par exemple les objets %Persistent ou les globales utilisées par la classe de transformation des données.

Un test unitaire pour une transformation commence par l'initialisation des données de contexte (par exemple, l'importation de tables de recherche). Ensuite, pour chaque objet source testé, il appelle la méthode Transform() et compare l'objet cible résultant de la transformation au résultat prévu.

Les résultats attendus peuvent être stockés sous forme de fichiers chargés par le test lors de l'exécution ou de blocs XData. Lorsque les entrées à tester sont nombreuses (par exemple, lors du test de plusieurs scénarios ADT HL7 v2.x complets), je trouve que les fichiers sont plus pratiques.

Exemple

Classe de test

Ce test utilise le module ks-iris-lib d'Open Exchange pour importer des messages HL7 à partir de blocs XData et comparer le message cible issu de la transformation au résultat prévu:

Class dc.SampleTransformTest Extends ks.lib.test.TestCase
{
 
Method TestTransform()
{
    #Dim sc as %Status
    #Dim ex as %Exception.AbstractException
    #Dim source,target,expected As EnsLib.HL7.Message
   
    s sc = $$$OK
    try {
        set source = ##class(ks.lib.hl7.Utils).ImportFromXData($classname(),"SourceHL7","2.3",.sc)
        $$$TOE(sc,sc)
        set expected = ##class(ks.lib.hl7.Utils).ImportFromXData($classname(),"ExpectedHL7","2.3",.sc)
        $$$TOE(sc,sc)
        $$$TOE(sc,##class(NullTranform).Transform(source,.target,$this))
        do $$$AssertTrue(..CompareHL7Messages(target,expected))
    } catch (ex) {
      s sc = ex.AsStatus()
    }
    do $$$AssertStatusOK(sc)
}
 
XData SourceHL7 [ MimeType = application/hl7 ]
{
MSH|^~\&|SPOCARD|EWHIN|JONES|EWHIN|199401040800||SIU^S13|021244SPOCARD|P|2.3|||AL|ER||
SCH|1994047^SCH001|1994567^SCH100|||||047^Referral|NORMAL|30|min|^^^199401091300^199401091330^^^^|0045^Jones^Harold^S^^^MD|555-4685|||087^Jensen^Helen^M^^^MD|555-9255||||BOOKED
NTE||The patient is going to be on vacation so cannot make previous appointmentscheduled on January 6.
PID||4875439|484848||Peterson^Joseph^^Jerome^SR|Brown|19401121|M|Jayjay||N 1234 Newport Highway^Mead^WA^99021||555-4685|||M|||999-99-4413|||||||||||
RGS|001|
AIP|001|032^JENSEN^HELEN|002^CARDIOLOGIST|||||||NO|BOOKED
}
 
XData ExpectedHL7 [ MimeType = application/hl7 ]
{
MSH|^~\&|SPOCARD|EWHIN|JONES|EWHIN|199401040800||SIU^S13|021244SPOCARD|P|2.3|||AL|ER||
SCH|1994047^SCH001|1994567^SCH100|||||047^Referral|NORMAL|30|min|^^^199401091300^199401091330^^^^|0045^Jones^Harold^S^^^MD|555-4685|||087^Jensen^Helen^M^^^MD|555-9255||||BOOKED
NTE||The patient is going to be on vacation so cannot make previous appointmentscheduled on January 6.
PID||4875439|484848||Peterson^Joseph^^Jerome^SR|Brown|19401121|M|Jayjay||N 1234 Newport Highway^Mead^WA^99021||555-4685|||M|||999-99-4413|||||||||||
RGS|001|
AIP|001|032^JENSEN^HELEN|002^CARDIOLOGIST|||||||NO|BOOKED
}
 
}
 

Classe de transformation

Class dc.NullTransform Extends Ens.DataTransform
{
 
ClassMethod Transform(source As EnsLib.HL7.Message, Output target As EnsLib.HL7.Message, aux As %String) As %Status
{
    #Dim sc as %Status
    #Dim ex as %Exception.AbstractException
    s sc = $$$OK
    try {
        s target = source.%ConstructClone(1)        
        s target.DocType = ..GetTargetDocType()
    } catch (ex) {
      s sc = ex.AsStatus()
    }
    return sc
}
 
ClassMethod GetSourceDocType() As %String
{
  return "2.3:SIU_S12"
}
 
ClassMethod GetTargetDocType() As %String
{
  return "2.3:SIU_S12"
}
 
}
Discussion (0)1
Connectez-vous ou inscrivez-vous pour continuer