Partilhar via


Criar testes de unidade a partir de execuções de fluxo de trabalho padrão em Aplicativos Lógicos do Azure com o Visual Studio Code

Aplica-se a: Aplicativos Lógicos do Azure (Padrão)

O teste de unidade é uma prática essencial que mantém seu aplicativo ou solução confiável e preciso durante todo o ciclo de vida de desenvolvimento de software. Os testes de unidade ajudam-no a validar de forma eficiente e sistemática os principais componentes da sua solução.

Para fluxos de trabalho de aplicativos lógicos padrão, você pode criar testes de unidade usando o Visual Studio Code e a extensão Azure Logic Apps (Standard). Esse recurso permite que você use execuções de fluxo de trabalho executadas anteriormente para criar testes de unidade e adaptá-los a cenários suportados por sua solução de aplicativo lógico. Essa abordagem oferece os seguintes benefícios:

  • Reutilizar execuções do fluxo de trabalho para gerar dados simulados para operações específicas no fluxo de trabalho.

    Esses dados permitem testar fluxos de trabalho sem precisar chamar serviços, sistemas ou APIs externos. Você economiza tempo e seu fluxo de trabalho permanece alinhado com o cenário real de execução do fluxo de trabalho.

  • Melhore a qualidade do fluxo de trabalho identificando e resolvendo possíveis problemas antes de implantar em outros ambientes.

  • Simplifique a integração do teste de unidade com seu processo de desenvolvimento, garantindo um comportamento consistente e preciso do fluxo de trabalho.

Este guia mostra como criar uma definição de teste de unidade a partir de uma execução de fluxo de trabalho. Essa definição simula as chamadas externas de cada operação de fluxo de trabalho sem alterar a lógica do fluxo de trabalho. Ao criar um teste de unidade a partir de uma execução de fluxo de trabalho, você obtém um projeto de teste de unidade que inclui duas pastas:

  • Uma pasta que contém classes fortemente tipadas para cada operação simulável em seu fluxo de trabalho.

  • Uma pasta para cada definição de teste de unidade, que inclui os seguintes arquivos:

    • Um arquivo JSON que representa as operações simuladas geradas em seu fluxo de trabalho.

    • Um arquivo C# que contém uma classe de exemplo e métodos que você usa para configurar suas próprias afirmações, confirmar se o fluxo de trabalho se comporta conforme o esperado e garantir que o fluxo de trabalho se comporte de forma confiável e previsível em seu ecossistema maior do Azure.

Pré-requisitos

Limitações e problemas conhecidos

  • Esta versão atualmente suporta apenas C# para criar testes de unidade.

  • Esta versão não suporta ações não simuladas. Certifique-se de que todas as ações no caminho de execução do fluxo de trabalho são simuladas.

  • Esta versão não suporta os seguintes tipos de ação:

    • Ações da conta de integração
    • Ações do Mapeador de Dados
    • Ações de código personalizado
    • Ações XML
    • Ações líquidas
    • Ações para codificar e decodificar EDI

Rever os conceitos básicos

A lista a seguir inclui conceitos básicos, mas importantes, sobre testes de unidade para fluxos de trabalho padrão:

  • Teste de unidade de aplicativo lógico

    Uma execução de fluxo de trabalho controlada que injeta objetos fictícios. Esses objetos representam o gatilho do fluxo de trabalho ou ações que dependem de serviços ou sistemas externos.

  • Ação simulada

    Uma ação de fluxo de trabalho que depende de um serviço ou sistema externo. Você pode converter essas ações em ações simuladas para criação e execução de testes de unidade.

Criar um teste de unidade a partir de um run de workflow

  1. No Visual Studio Code, abra seu projeto de aplicativo lógico padrão.

  2. Na barra de ferramentas do Visual Studio Code, no menu Executar, selecione Iniciar Depuração. (Teclado: pressione F5)

  3. Volte para a janela do Explorer. No seu projeto, expanda a pasta de definição do fluxo de trabalho.

  4. Abra o menu de atalho workflow.json e selecione Visão geral.

  5. Na página de visão geral, em Histórico de execução, selecione a execução do fluxo de trabalho a ser usada para criar um teste de unidade.

    A captura de tela mostra o código do Visual Studio com projeto de aplicativo lógico padrão, o modo de depuração em execução, a página de visão geral do fluxo de trabalho aberta e a execução do fluxo de trabalho selecionado.

  6. Na barra de ferramentas do histórico de execução, selecione Criar teste unitário a partir da execução.

    A captura de tela mostra o código do Visual Studio, a página de histórico de execução do fluxo de trabalho padrão e o comando selecionado para criar o teste de unidade.

  7. Forneça um nome a ser usado para o teste de unidade, classe de teste de unidade e arquivo C#.

    Na janela Explorer , uma nova pasta de projeto chamada Testes aparece na pasta de projeto do aplicativo lógico. A pasta Testes contém as seguintes pastas e arquivos:

    A captura de tela mostra o Visual Studio Code, o projeto de aplicativo lógico padrão e a pasta Testes com pastas e arquivos de teste de unidade.

    Pasta ou ficheiro Descrição
    Tests
    || <logic-app-name>
    Na pasta Tests, uma pasta <logic-app-name> aparece quando se adicionam testes de unidade a um projeto de aplicação lógica.
    Tests
    || <logic-app-name>
    ||| <workflow-name>
    Na pasta <logic-app-name>, uma pasta <workflow-name> aparece quando se adicionam testes de unidade para um fluxo de trabalho.
    Tests
    || <logic-app-name>
    ||| <workflow-name>
    |||| MockOutputs
    |||||<operation-name-outputs>.cs
    Na pasta <workflow-name>, a pasta MockOutputs contém um ficheiro C# (.cs) com classes fortemente tipadas para cada operação de conector no fluxo de trabalho. Cada nome de arquivo .cs usa o seguinte formato:

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

    Se uma operação de conector tiver contratos dinâmicos, uma classe será exibida para cada tipo dinâmico. Um tipo dinâmico refere-se a um parâmetro de operação que tem diferentes entradas e saídas com base no valor fornecido para esse parâmetro. Você pode usar essas classes para estender seus testes de unidade e criar novas simulações do zero.
    Tests
    || <logic-app-name>
    ||| <workflow-name>
    |||| <unit-test-name>
    ||||| <unit-test-name>-mock.json
    ||||| <unit-test-name>.cs
    Na pasta <workflow-name>, a pasta <unit-test-name> contém os seguintes ficheiros:

    - O <unit-test-name>-mock.json arquivo contém uma representação JSON para as simulações geradas, com base na execução do fluxo de trabalho que criou o teste de unidade.

    - O <unit-test-name>.cs arquivo contém uma classe C# de exemplo e métodos que usam o *-mock.json arquivo para executar e afirmar resultados. Você pode editar esse arquivo para corresponder aos seus cenários de teste específicos.

Revise o arquivo *-mock.json

Este ficheiro tem as seguintes secções principais:

triggerMocks seção

A triggerMocks seção contém o resultado simulado do gatilho do fluxo de trabalho. Esta seção é necessária para iniciar a execução do fluxo de trabalho, conforme mostrado no exemplo a seguir:

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

actionMocks seção

Para cada ação simulável em uma execução de fluxo de trabalho, a actionMocks seção contém uma ação simulada e garante a execução controlada do fluxo de trabalho.

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

Revise o arquivo de teste de unidade *.cs

Esta classe de teste de unidade fornece uma estrutura para testar fluxos de trabalho de aplicativos lógicos padrão simulando gatilhos e ações. Essa classe permite testar fluxos de trabalho sem realmente chamar serviços externos ou APIs.

Estrutura de classe de teste

Uma classe de teste de unidade típica usa a seguinte estrutura:

[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étodo Setup()

Esse método instancia a TestExecutor classe usando o caminho para o arquivo de configuração de definições de teste. O método é executado antes de cada execução de teste e cria uma nova instância do TestExecutor.

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

Métodos de ensaio por amostragem

A seção a seguir descreve métodos de teste de exemplo que você pode usar em sua classe de teste de unidade.

Teste estático de dados simulados

O método a seguir mostra como usar dados fictícios estáticos para testar seu fluxo de trabalho. Nesse método, você pode concluir as seguintes tarefas:

  • Defina valores de propriedade em suas ações simuladas.
  • Execute o fluxo de trabalho com os dados fictícios configurados.
  • Confirme se a execução foi bem-sucedida.
[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);
}

Teste de dados simulados dinâmicos

O método a seguir mostra como usar dados fictícios dinâmicos através de métodos de retorno de chamada. Essa abordagem oferece duas opções que geram dados fictícios dinamicamente:

Ambas as abordagens permitem criar respostas dinâmicas com base no contexto de execução do teste de unidade.

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

Teste de cenário de erro

O método a seguir mostra como testar condições de falha. Nesse método, você pode concluir as seguintes tarefas:

  • Configure ações simuladas para falhar com códigos de erro e mensagens específicos.
  • Confirme se o fluxo de trabalho lida corretamente com essas condições de erro.
[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étodos auxiliares

A seção a seguir descreve os métodos usados pelos métodos de teste de exemplo. Os métodos auxiliares aparecem sob os métodos de teste na definição de classe.

GetTestMockDefinition()

O método a seguir carrega a definição simulada de um arquivo JSON. Você pode editar esse método se seus dados fictícios estiverem armazenados em um local ou formato diferente.

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étodo de callback

O método a seguir gera dinamicamente dados fictícios. O nome do método varia com base no nome da ação simulada nos métodos de teste para dados simulados estáticos ou dinâmicos. Você pode editar esse método para retornar diferentes respostas simuladas com base em seus requisitos de cenário de teste ou usá-lo como um modelo para criar seus próprios métodos de retorno de chamada dinâmico.

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

        }
    );
}