Condividi tramite


Creare test unitari dalle esecuzioni del flusso di lavoro Standard in Azure Logic Apps con Visual Studio Code

Si applica a: Azure Logic Apps (Standard)

Gli unit test sono una pratica essenziale che consente di mantenere l'app o la soluzione affidabile e accurata nel ciclo di vita dello sviluppo software. Gli unit test consentono di convalidare in modo efficiente e sistematico i componenti chiave nella soluzione.

Per i flussi di lavoro delle app per la logica Standard, è possibile creare unit test usando Visual Studio Code e l'estensione App per la logica di Azure (Standard). Questa funzionalità consente di usare le esecuzioni del flusso di lavoro eseguite in precedenza per creare unit test e personalizzarle in base agli scenari supportati dalla soluzione dell'app per la logica. Questa funzione offre i seguenti vantaggi:

  • Riutilizzare le esecuzioni del flusso di lavoro per generare dati fittizi per operazioni specifiche nel flusso di lavoro.

    Questi dati consentono di testare i flussi di lavoro senza dover chiamare servizi esterni, sistemi o API. Si risparmia tempo e il flusso di lavoro rimane allineato allo scenario di esecuzione effettivo del flusso di lavoro.

  • Migliorare la qualità del flusso di lavoro identificando e risolvendo potenziali problemi prima di eseguire la distribuzione in altri ambienti.

  • Semplificare l'integrazione degli unit test con il processo di sviluppo, garantendo al tempo stesso un comportamento coerente e accurato del flusso di lavoro.

Questa guida illustra come creare una definizione di unit test da un'esecuzione del flusso di lavoro. Questa definizione simula le chiamate esterne da ogni operazione del flusso di lavoro senza modificare la logica del flusso di lavoro. Quando si crea uno unit test da un'esecuzione del flusso di lavoro, si ottiene un progetto di unit test che include due cartelle:

  • Una cartella che contiene classi fortemente tipizzate per ogni operazione simulabile nel flusso di lavoro.

  • Cartella per ogni definizione di unit test, che include i file seguenti:

    • File JSON che rappresenta le operazioni fittizie generate nel flusso di lavoro.

    • Un file C# che contiene una classe e metodi di esempio usati per configurare le proprie asserzioni, verificare che il flusso di lavoro si comporti come previsto e assicurarsi che il flusso di lavoro si comporti in modo affidabile e prevedibile nell'ecosistema di Azure più grande.

Prerequisiti

Limitazioni e problemi noti

  • Questa versione supporta attualmente solo C# per la creazione di unit test.

  • Questa versione non supporta azioni non simulate. Verificare che tutte le azioni nel percorso di esecuzione del flusso di lavoro siano simulate.

  • Questa versione non supporta i tipi di azione seguenti:

    • Azioni dell'account di integrazione
    • Azioni di Data Mapper
    • Azioni di codice personalizzate
    • Azioni XML
    • Azioni liquide
    • Azioni di codifica e decodifica EDI

Esaminare i concetti di base

L'elenco seguente include concetti di base ma importanti sugli unit test per i flussi di lavoro Standard:

  • Test unitario dell'app logica

    Esecuzione controllata del flusso di lavoro che inserisce oggetti fittizi. Questi oggetti rappresentano il trigger o le azioni del flusso di lavoro che dipendono da servizi o sistemi esterni.

  • Azione fittizia

    Azione del flusso di lavoro che dipende da un servizio o un sistema esterno. È possibile convertire queste azioni in azioni fittizie per la creazione e l'esecuzione di unit test.

Crea un unit test da un'esecuzione del flusso di lavoro

  1. In Visual Studio Code aprire il progetto di app per la logica Standard.

  2. Sulla barra degli strumenti di Visual Studio Code scegliere Avvia debug dal menu Esegui. (Tastiera: Premere F5)

  3. Tornare alla finestra Esplora file. Nel progetto espandere la cartella di definizione del flusso di lavoro.

  4. Aprire il menu di scelta rapida workflow.json e selezionare Panoramica.

  5. Nella pagina di panoramica, in Cronologia di esecuzione, selezionare l'esecuzione del flusso di lavoro da usare per la creazione di un test unitario.

    Screenshot che mostra Visual Studio Code con il progetto di app logica Standard, la modalità di debug in esecuzione, la pagina di panoramica aperta del flusso di lavoro e il flusso di lavoro selezionato in esecuzione.

  6. Sulla barra degli strumenti della cronologia di esecuzione selezionare Crea unit test dall'esecuzione.

    Screenshot che mostra Visual Studio Code, la pagina della cronologia di esecuzione del flusso di lavoro Standard e il comando selezionato per creare unit test.

  7. Specificare un nome da usare per lo unit test, la classe unit test e il file C#.

    Nella finestra Esplora risorse viene visualizzata una nuova cartella di progetto denominata Tests nella cartella del progetto dell'app per la logica. La cartella Tests contiene le cartelle e i file seguenti:

    Screenshot che mostra Visual Studio Code, progetto di applicazione logica standard e cartella Test con cartelle e file di test unitari.

    File o cartella Descrizione
    Tests
    || <logic-app-name>
    Quando si aggiungono unit test a un progetto di logica di app, nella cartella Tests appare una cartella <logic-app-name>.
    Tests
    || <logic-app-name>
    ||| <workflow-name>
    Nella cartella <logic-app-name> appare una cartella <workflow-name> quando vengono aggiunti degli unit test per un flusso di lavoro.
    Tests
    || <logic-app-name>
    ||| <workflow-name>
    |||| MockOutputs
    < operation-name-outputs >|||||.cs
    Nella cartella <workflow-name>, la cartella MockOutputs contiene un file C# (.cs) con classi tipizzate per ogni operazione del connettore nel flusso di lavoro. Ogni .cs nome file usa il formato seguente:

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

    Se un'operazione del connettore ha contratti dinamici, viene visualizzata una classe per ogni tipo dinamico. Un tipo dinamico fa riferimento a un parametro dell'operazione con input e output diversi in base al valore fornito per tale parametro. È possibile usare queste classi per estendere gli unit test e creare nuove simulazioni da zero.
    Tests
    || <logic-app-name>
    ||| <workflow-name>
    |||| <unit-test-name>
    ||||| <unit-test-name>-mock.json
    ||||| <unit-test-name>.cs
    Nella cartella <workflow-name>, la cartella <unit-test-name> contiene i seguenti file:

    - Il <unit-test-name>-mock.json file contiene una rappresentazione JSON per le simulazioni generate, in base all'esecuzione del flusso di lavoro che ha creato lo unit test.

    - Il <unit-test-name>.cs file contiene una classe e metodi C# di esempio che usano il *-mock.json file per eseguire ed asserire i risultati. È possibile modificare questo file in modo che corrisponda agli scenari di test specifici.

Esaminare il file *-mock.json

Questo file include le sezioni principali seguenti:

Sezione triggerMocks

La triggerMocks sezione contiene il risultato fittizio del trigger del flusso di lavoro. Questa sezione è necessaria per avviare l'esecuzione del flusso di lavoro, come illustrato nell'esempio seguente:

{
    "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": {...}
}

Sezione actionMocks

Per ogni azione fittizia in un'esecuzione del flusso di lavoro, la actionMocks sezione contiene un'azione fittizia e garantisce l'esecuzione controllata del flusso di lavoro.

{
    "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": {}
            }
        }
    }
}

Esaminare il file di unit test *.cs

Questa classe di test unitario fornisce un framework per testare i flussi di lavoro dell'applicazione logica Standard mediante la simulazione di trigger e azioni. Questa classe consente di testare i flussi di lavoro senza chiamare effettivamente servizi esterni o API.

Struttura della classe di test

Una tipica classe di unit test usa la struttura seguente:

[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.
}

Metodo Setup()

Questo metodo crea un'istanza della TestExecutor classe usando il percorso del file di configurazione delle impostazioni di test. Il metodo viene eseguito prima di ogni esecuzione di test e crea una nuova istanza di TestExecutor.

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

Metodi di test di esempio

La sezione seguente descrive i metodi di test di esempio che è possibile usare nella classe di unit test.

Test di dati fittizi statici

Il metodo seguente illustra come usare dati fittizi statici per testare il flusso di lavoro. In questo metodo è possibile completare le attività seguenti:

  • Imposta i valori delle proprietà sulle azioni simulate.
  • Eseguire il flusso di lavoro con i dati fittizi configurati.
  • Verificare che l'esecuzione sia riuscita.
[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 di dati fittizi dinamici

Il metodo seguente illustra come usare dati fittizi dinamici con metodi di callback. Questo approccio offre due opzioni che generano dinamicamente dati fittizi:

Entrambi gli approcci consentono di creare risposte dinamiche in base al contesto di esecuzione degli unit test.

[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 dello scenario di errore

Il metodo seguente illustra come testare le condizioni di errore. In questo metodo è possibile completare le attività seguenti:

  • Configurare azioni fittizie per l'esito negativo con codici di errore e messaggi specifici.
  • Verificare che il flusso di lavoro gestisca correttamente queste condizioni di errore.
[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);
}

Metodi di supporto

Nella sezione seguente vengono descritti i metodi usati dai metodi di test di esempio. I metodi helper appaiono sotto i metodi di test nella definizione della classe.

GetTestMockDefinition()

Il metodo seguente carica la definizione fittizia da un file JSON. È possibile modificare questo metodo se i dati fittizi vengono archiviati in una posizione o in un formato diverso.

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));
}

Metodo di callback

Il metodo seguente genera dinamicamente dati fittizi. Il nome del metodo varia in base al nome dell'azione fittizia nei metodi di test per i dati fittizi statici o dinamici. È possibile modificare questo metodo per restituire risposte fittizie diverse in base ai requisiti dello scenario di test o usarlo come modello per creare metodi di callback dinamici personalizzati.

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()

        }
    );
}