Partager via


Créer des tests unitaires à partir d’exécutions de flux de travail Standard dans Azure Logic Apps avec Visual Studio Code

S’applique à : Azure Logic Apps (Standard)

Le test unitaire est une pratique essentielle qui maintient votre application ou votre solution fiable et précise tout au long du cycle de vie du développement logiciel. Les tests unitaires vous aident à valider efficacement et systématiquement les composants clés de votre solution.

Pour les flux de travail d’application logique standard, vous pouvez créer des tests unitaires à l’aide de Visual Studio Code et de l’extension Azure Logic Apps (Standard). Cette fonctionnalité vous permet d’utiliser des exécutions de flux de travail précédemment exécutées pour créer des tests unitaires et les adapter aux scénarios pris en charge par votre solution d’application logique. Cette approche offre les avantages suivants :

  • Réutilisez les exécutions de flux de travail pour générer des données fictives pour les opérations spécifiques dans le flux de travail.

    Ces données vous permettent de tester les flux de travail sans avoir à appeler des services externes, des systèmes ou des API. Vous gagnez du temps et votre flux de travail reste aligné sur le scénario d’exécution de flux de travail réel.

  • Améliorez la qualité du flux de travail en identifiant et en traitant les problèmes potentiels avant de les déployer dans d’autres environnements.

  • Simplifiez l’intégration des tests unitaires à votre processus de développement, tout en garantissant un comportement de flux de travail cohérent et précis.

Ce guide montre comment créer une définition de test unitaire à partir d’une exécution de flux de travail. Cette définition simule les appels externes de chaque opération de flux de travail sans modifier la logique du flux de travail. Lorsque vous créez un test unitaire à partir d’une exécution de flux de travail, vous obtenez un projet de test unitaire qui comprend deux dossiers :

  • Un dossier qui contient des classes fortement typées pour chaque opération simulable dans votre workflow.

  • Un dossier pour chaque définition de test unitaire, qui inclut les fichiers suivants :

    • Fichier JSON qui représente les opérations simulées générées dans votre flux de travail.

    • Fichier C# qui contient un exemple de classe et de méthodes que vous utilisez pour configurer vos propres assertions, vérifiez que le flux de travail se comporte comme prévu et assurez-vous que le flux de travail se comporte de manière fiable et prévisible dans votre plus grand écosystème Azure.

Conditions préalables

Limitations et problèmes connus

  • Cette version prend actuellement en charge uniquement C# pour la création de tests unitaires.

  • Cette version ne prend pas en charge les actions non simulées. Assurez-vous que toutes les actions du chemin d’exécution du flux de travail sont simulées.

  • Cette version ne prend pas en charge les types d’actions suivants :

    • Actions du compte d'intégration
    • Actions du mappeur de données
    • Actions de code personnalisées
    • Actions XML
    • Actions liquides
    • Actions d'encodage et de décodage EDI

Passer en revue les concepts de base

La liste suivante inclut des concepts de base mais importants sur les tests unitaires pour les flux de travail Standard :

  • Test unitaire d’application logique

    Exécution contrôlée du flux de travail qui injecte des objets fictifs. Ces objets représentent le déclencheur de flux de travail ou les actions qui dépendent de services ou de systèmes externes.

  • Action simulable

    Action de flux de travail qui dépend d’un service ou d’un système externe. Vous pouvez convertir ces actions en actions fictives pour la création et l’exécution de tests unitaires.

Créer un test unitaire à partir d’une exécution de flux de travail

  1. Dans Visual Studio Code, ouvrez votre projet d’application logique Standard.

  2. Dans la barre d’outils de Visual Studio Code, dans le menu Exécuter , sélectionnez Démarrer le débogage. (Clavier : Appuyez sur F5)

  3. Revenez à la fenêtre Explorateur . Dans votre projet, développez le dossier de définition de flux de travail.

  4. Ouvrez le menu contextuel workflow.json , puis sélectionnez Vue d’ensemble.

  5. Dans la page vue d’ensemble, sous Historique des exécutions, sélectionnez l’exécution du flux de travail à utiliser pour créer un test unitaire.

    Capture d’écran montrant Visual Studio Code avec le projet d’application logique Standard, le mode débogage en cours d’exécution, la page vue d’ensemble du flux de travail ouverte et l’exécution de flux de travail sélectionnée.

  6. Dans la barre d’outils de l’historique des exécutions, sélectionnez Créer un test unitaire à partir de l’exécution.

    Capture d’écran montrant Visual Studio Code, page Historique des exécutions de flux de travail Standard et commande sélectionnée pour créer un test unitaire.

  7. Fournissez un nom à utiliser pour le fichier de test unitaire, de classe de test unitaire et de fichier C#.

    Dans la fenêtre Explorateur , un nouveau dossier de projet nommé Tests s’affiche sous votre dossier de projet d’application logique. Le dossier Tests contient les dossiers et fichiers suivants :

    Capture d’écran montrant Visual Studio Code, le projet d’application logique standard et le dossier Tests avec des dossiers et des fichiers de test unitaires.

    Fichier ou dossier Descriptif
    Tests
    || <logic-app-name>
    Dans le Tests dossier, un <logic-app-name> dossier s’affiche lorsque vous ajoutez des tests unitaires à un projet d’application logique.
    Tests
    || <logic-app-name>
    ||| <workflow-name>
    Dans le <logic-app-name> dossier, un <workflow-name> dossier s’affiche lorsque vous ajoutez des tests unitaires pour un flux de travail.
    Tests
    || <logic-app-name>
    ||| <workflow-name>
    |||| MockOutputs
    < operation-name-outputs >||||| .cs
    Dans le <workflow-name> dossier, le MockOutputs dossier contient un fichier C# (.cs) avec des classes fortement typées pour chaque opération de connecteur dans le flux de travail. Chaque nom de fichier .cs utilise le format suivant :

    < operation-name >[Trigger\|Action]Output.cs

    Si une opération de connecteur a des contrats dynamiques, une classe apparaît pour chaque type dynamique. Un type dynamique fait référence à un paramètre d’opération qui a différentes entrées et sorties en fonction de la valeur fournie pour ce paramètre. Vous pouvez utiliser ces classes pour étendre vos tests unitaires et créer de nouvelles maquettes à partir de zéro.
    Tests
    || <logic-app-name>
    ||| <workflow-name>
    |||| <unit-test-name>
    ||||| <unit-test-name>-mock.json
    ||||| <unit-test-name>.cs
    Dans le <workflow-name> dossier, le <unit-test-name> dossier contient les fichiers suivants :

    - Le fichier <unit-test-name>-mock.json contient une représentation JSON pour les mocks générés, en fonction de l’exécution du workflow qui a créé le test unitaire.

    - Le <unit-test-name>.cs fichier contient un exemple de classe C# et de méthodes qui utilisent le *-mock.json fichier pour exécuter et déclarer les résultats. Vous pouvez modifier ce fichier pour qu’il corresponde à vos scénarios de test spécifiques.

Passez en revue le fichier *-mock.json

Ce fichier comporte les sections principales suivantes :

Section triggerMocks

La section triggerMocks contient le résultat fictif du déclencheur de processus. Cette section est requise pour démarrer l’exécution du flux de travail, comme indiqué dans l’exemple suivant :

{
    "triggerMocks": {
        "When_messages_are_available_in_a_queue_(peek-lock)": {
            "name": "When_messages_are_available_in_a_queue_(peek-lock)",
            "status": "Succeeded",
            "outputs": {
                "body": {
                    "contentData": {
                        "messageId": "1234",
                        "status": "new",
                        "contentType": "application/json",
                        "userProperties": {},
                        "scheduledEnqueueTimeUtc": "1/1/0001 12:00:00 AM",
                        "timeToLive": "14.00:00:00",
                        "deliveryCount": 1,
                        "enqueuedSequenceNumber": 0,
                        "enqueuedTimeUtc": "2025-04-07T01:10:09.738Z",
                        "lockedUntilUtc": "2025-04-07T01:11:09.769Z",
                        "lockToken": "78232fa8-03cf-4baf-b1db-3375a64e0ced",
                        "sequenceNumber": 5
                    }
                }
            }
        }
    },
    "actionMocks": {...}
}

Section actionMocks

Pour chaque action simulable dans une exécution de flux de travail, la section actionMocks contient une action simulée et assure l’exécution contrôlée du flux de travail.

{
    "triggerMocks": {...},
    "actionMocks": {
        "Call_External_API": {
            "name": "Call_External_API",
            "status": "Succeeded",
            "outputs": {
                "statusCode": 200,
                "body": {
                    "status": "Awesome!"
                }
            }
        },
        "CompleteMessage": {
            "name": "CompleteMessage",
            "status": "Succeeded",
            "outputs": {
                "statusCode": "OK",
                "body": {}
            }
        }
    }
}

Passez en revue le fichier *.cs de test unitaire

Cette classe de test unitaire fournit une infrastructure pour tester les flux logiques d'application standard en simulant des déclencheurs et des actions. Cette classe vous permet de tester les flux de travail sans appeler réellement des services externes ou des API.

Structure de classe de test

Une classe de test unitaire classique utilise la structure suivante :

[TestClass]
public class <unit-test-name>
{
    public TestExecutor TestExecutor;

    [TestInitialize]
    public void Setup()
    {
        this.TestExecutor = new TestExecutor("<workflow-name>/testSettings.config");
    }

    // Add test methods here.

    // Add helper methods here.
}

Méthode Setup()

Cette méthode instancie la TestExecutor classe à l’aide du chemin d’accès à votre fichier de configuration des paramètres de test. La méthode s’exécute avant chaque exécution de test et crée une nouvelle instance de TestExecutor.

[TestInitialize]
public void Setup()
{
    this.TestExecutor = new TestExecutor("<workflow-name>/testSettings.config");
}

Exemples de méthodes de test

La section suivante décrit les exemples de méthodes de test que vous pouvez utiliser dans votre classe de test unitaire.

Test de données fictives statiques

La méthode suivante montre comment utiliser des données fictives statiques pour tester votre flux de travail. Dans cette méthode, vous pouvez effectuer les tâches suivantes :

  • Définissez les valeurs des propriétés de vos actions simulées.
  • Exécutez le flux de travail avec les données fictives configurées.
  • Vérifiez que l’exécution a réussi.
[TestMethod]
public async Task <workflow-name>_<unit-test-name>_ExecuteWorkflow_SUCCESS_Sample1()
{
    // PREPARE mock: Generate mock action and trigger data.
    var mockData = this.GetTestMockDefinition();
    var sampleActionMock = mockData.ActionMocks["Call_External_API"];
    sampleActionMock.Outputs["your-property-name"] = "your-property-value";

    // ACT: Create the UnitTestExecutor instance. Run the workflow with mock data.
    var testRun = await this.TestExecutor
        .Create()
        .RunWorkflowAsync(testMock: mockData).ConfigureAwait(continueOnCapturedContext: false);

    // ASSERT: Confirm successful workflow execution and that the status is 'Succeeded'.
    Assert.IsNotNull(value: testRun);
    Assert.AreEqual(expected: TestWorkflowStatus.Succeeded, actual: testRun.Status);
}

Test dynamique des données fictives

La méthode suivante montre comment utiliser des données fictives dynamiques avec des méthodes de rappel. Cette approche vous offre deux options qui génèrent dynamiquement des données fictives :

Les deux approches vous permettent de créer des réponses dynamiques basées sur le contexte d’exécution de test unitaire.

[TestMethod]
public async Task <workflow-name>_<unit-test-name>_ExecuteWorkflow_SUCCESS_Sample2()
{
    // PREPARE: Generate mock action and trigger data.
    var mockData = this.GetTestMockDefinition();
    
    // OPTION 1: Define a callback class.
    mockData.ActionMocks["Call_External_API"] = new CallExternalAPIActionMock(
        name: "Call_External_API", 
        onGetActionMock: CallExternalAPIActionMockOutputCallback);

    // OPTION 2: Define an inline lambda function.
    mockData.ActionMocks["Call_External_API"] = new CallExternalAPIActionMock(
        name: "Call_External_API", 
        onGetActionMock: (testExecutionContext) =>
        {
            return new CallExternalAPIActionMock(
                status: TestWorkflowStatus.Succeeded,
                outputs: new CallExternalAPIActionOutput {

                    // If this account contains a JObject Body, 
                    // set the properties you want here:
                    // Body = "something".ToJObject()

                }
            );
        });
        
    // ACT: Create UnitTestExecutor instance. Run the workflow with mock data.
    var testRun = await this.TestExecutor
        .Create()
        .RunWorkflowAsync(testMock: mockData).ConfigureAwait(continueOnCapturedContext: false);

    // ASSERT: Confirm successful workflow execution and that the status is 'Succeeded'.
    Assert.IsNotNull(value: testRun);
    Assert.AreEqual(expected: TestWorkflowStatus.Succeeded, actual: testRun.Status);
}

Test du scénario d’erreur

La méthode suivante montre comment tester les conditions d’échec. Dans cette méthode, vous pouvez effectuer les tâches suivantes :

  • Configurez les actions simulées pour échouer avec des codes d’erreur et des messages spécifiques.
  • Vérifiez que le flux de travail gère correctement ces conditions d’erreur.
[TestMethod]
public async Task <workflow-name>_<unit-test-name>_ExecuteWorkflow_FAILED_Sample3()
{
    // PREPARE: Generate mock action and trigger data.
    var mockData = this.GetTestMockDefinition();
    var mockError = new TestErrorInfo(code: ErrorResponseCode.BadRequest, message: "Input is invalid.");
    mockData.ActionMocks["Call_External_API"] = new CallExternalAPIActionMock(
        status: TestWorkflowStatus.Failed, 
        error: mockError);

    // ACT: Create UnitTestExecutor instance. Run the workflow with mock data.
    var testRun = await this.TestExecutor
        .Create()
        .RunWorkflowAsync(testMock: mockData).ConfigureAwait(continueOnCapturedContext: false);

    // ASSERT: Confirm successful workflow execution and that the status is 'Succeeded'.
    Assert.IsNotNull(value: testRun);
    Assert.AreEqual(expected: TestWorkflowStatus.Failed, actual: testRun.Status);
}

Méthodes d’assistance

La section suivante décrit les méthodes utilisées par les exemples de méthodes de test. Les méthodes d’assistance apparaissent sous les méthodes de test dans la définition de classe.

GetTestMockDefinition()

La méthode suivante charge la définition fictive à partir d’un fichier JSON. Vous pouvez modifier cette méthode si vos données fictifs sont stockées dans un autre emplacement ou format.

private TestMockDefinition GetTestMockDefinition()
{
    var mockDataPath = Path.Combine(TestExecutor.rootDirectory, "Tests", TestExecutor.logicAppName, 
        TestExecutor.workflow, "<unit-test-name>", "<unit-test-name>-mock.json");
    return JsonConvert.DeserializeObject<TestMockDefinition>(File.ReadAllText(mockDataPath));
}

Méthode de rappel

La méthode suivante génère dynamiquement des données fictives. Le nom de la méthode varie en fonction du nom de l’action simulée dans les méthodes de test pour les données fictives statiques ou dynamiques. Vous pouvez modifier cette méthode pour retourner différentes réponses fictives en fonction des exigences de votre scénario de test ou l’utiliser comme modèle pour créer vos propres méthodes de rappel dynamique.

public CallExternalAPIActionMock CallExternalAPIActionMockOutputCallback(TestExecutionContext context)
{
    // Sample mock data: Dynamically change the mocked data for "actionName".
    return new CallExternalAPIActionMock(
        status: TestWorkflowStatus.Succeeded,
        outputs: new CallExternalAPIActionOutput {

            // If this account contains a JObject Body, 
            // set the properties you want here:
            // Body = "something".ToJObject()

        }
    );
}