Esercizio - Eseguire test di carico in Azure Pipelines

Completato

In questa sezione viene eseguito il piano di test creato nella pipeline di versione. Il piano di test usa Apache JMeter per eseguire test di carico.

Ecco come vengono eseguiti i test:

  • Recuperare ed eseguire il checkout di un ramo Git che implementi i test.
  • Modificare la pipeline per installare JMeter, eseguire il piano di test, trasformare i risultati in JUnit e pubblicare i risultati in Azure Pipelines.
  • Eseguire il push del ramo in GitHub, osservare l'esecuzione dei test in Azure Pipelines e quindi esaminare i risultati.

Recuperare il ramo da GitHub

In questa sezione verrà recuperato il ramo jmeter da GitHub e si eseguirà il checkout o il passaggio a tale ramo.

Questo ramo contiene il progetto Space Game usato nei moduli precedenti. Contiene anche una configurazione di Azure Pipelines per iniziare.

  1. Aprire il terminale integrato in Visual Studio Code.

  2. Eseguire i comandi git fetch e git checkout seguenti per scaricare un ramo denominato jmeter dal repository di Microsoft e passare a tale ramo:

    git fetch upstream jmeter
    git checkout -B jmeter upstream/jmeter
    

    Tenere presente che upstream si riferisce al repository GitHub Microsoft. La configurazione Git del progetto riconosce il repository remoto upstream perché questa relazione viene configurata quando si esegue la copia tramite fork del progetto dal repository Microsoft e lo si clona in locale.

    In breve, si eseguirà il push di questo ramo al repository GitHub personale, noto come origin.

  3. Facoltativamente, in Visual Studio Code aprire il file azure-pipelines.yml. Rivedere la configurazione iniziale.

    La configurazione è simile a quelle create nei moduli precedenti in questo percorso di apprendimento. Esegue la compilazione solo della configurazione Release dell'applicazione. Per brevità, omette i trigger, le approvazioni manuali e i test configurati nei moduli precedenti.

    Nota

    Una configurazione più solida potrebbe specificare i rami che fanno parte del processo di compilazione. Ad esempio, per verificare la qualità del codice, è possibile eseguire unit test ogni volta che si esegue il push di una modifica in qualsiasi ramo. È anche possibile distribuire l'applicazione in un ambiente che esegue test più completi. Questa distribuzione viene tuttavia usata solo quando si ha una richiesta pull, quando si ha una versione finale candidata o quando si esegue il merge del codice in main.

    Per altre informazioni, vedere Implementare un flusso di lavoro di codice nella pipeline di compilazione usando Git e GitHub e Trigger della pipeline di compilazione.

  4. Facoltativamente, in Visual Studio Code è possibile estrarre il file del piano di test JMeter, LoadTest.jmx e la trasformazione XLST, JMeter2JUnit.xsl. Il file XLST trasforma l'output JMeter in JUnit in modo che Azure Pipelines possa visualizzare i risultati.

Aggiungere variabili ad Azure Pipelines

Il piano di test originale del team fornisce un valore hardcoded per il nome host del sito Web di Space Game che viene eseguito nell'ambiente di staging.

Per rendere più flessibile il piano di test, verrà usata una proprietà JMeter. Si pensi a una proprietà come a una variabile che è possibile impostare dalla riga di comando.

Ecco come viene definita la variabile hostname in JMeter:

Screenshot of setting the hostname variable in Apache JMeter.

Ecco il modo in cui la variabile hostname usa la funzione __P per leggere la variabile hostname.

Screenshot for reading the hostname variable in Apache JMeter.

Il file del piano di test corrispondente, LoadTest.jmx, specifica questa variabile e la usa per impostare il nome host.

Quando si esegue JMeter dalla riga di comando, si usa l'argomento -J per impostare la proprietà hostname. Ecco un esempio:

apache-jmeter-5.4.3/bin/./jmeter -n -t LoadTest.jmx -o Results.xml -Jhostname=tailspin-space-game-web-staging-1234.azurewebsites.net

Qui è possibile impostare la variabile STAGING_HOSTNAME in Azure Pipelines. Questa variabile punta al nome host del sito in esecuzione nel servizio app nell'ambiente di staging. Si imposta anche jmeterVersion per specificare la versione di JMeter da installare.

Quando l'agente viene eseguito, queste variabili vengono esportate automaticamente nell'agente come variabili di ambiente, in modo che la configurazione della pipeline possa eseguire JMeter in questo modo:

apache-jmeter-5.4.3/bin/./jmeter -n -t LoadTest.jmx -o Results.xml -Jhostname=$(STAGING_HOSTNAME)

A questo punto, aggiungere le variabili della pipeline prima di aggiornare la configurazione della pipeline. A questo scopo:

  1. In Azure DevOps passare al progetto Space Game - Web - Test non funzionali.

  2. In Pipeline, selezionare Libreria.

  3. Selezionare il gruppo di variabili Rilascio.

  4. In Variabili, selezionare + Aggiungi.

  5. Immettere STAGING_HOSTNAME come nome della variabile. Come valore, immettere l'URL dell'istanza del servizio app corrispondente all'ambiente di staging, ad esempio tailspin-space-game-web-staging-1234.azurewebsites.net.

    Importante

    Non includere il prefisso del protocollo http:// o https:// nel valore. JMeter fornisce il protocollo durante l'esecuzione dei test.

  6. Aggiungere una seconda variabile denominata jmeterVersion. Come valore, specificare 5.4.3.

    Nota

    Questa è la versione di JMeter usata l'ultima volta per testare il modulo. Per ottenere la versione più recente, vedere Download Apache JMeter.

  7. Per salvare la variabile nella pipeline, selezionare Salva nella parte superiore della pagina.

    Il gruppo di variabili è simile a quello illustrato nell'immagine seguente:

    Screenshot of Azure Pipelines, showing the variable group. The group contains five variables.

Modificare la configurazione della pipeline

In questa sezione si modificherà la pipeline per eseguire i test di carico durante la fase di staging.

  1. In Visual Studio Code aprire il file azure-pipelines.yml. Modificare quindi il file come segue:

    Suggerimento

    Puoi sostituire l'intero file o aggiornare solo il percorso evidenziato.

    trigger:
    - '*'
    
    variables:
      buildConfiguration: 'Release'
    
    stages:
    - stage: 'Build'
      displayName: 'Build the web application'
      jobs:
      - job: 'Build'
        displayName: 'Build job'
        pool:
          vmImage: 'ubuntu-20.04'
          demands:
          - npm
    
        variables:
          wwwrootDir: 'Tailspin.SpaceGame.Web/wwwroot'
          dotnetSdkVersion: '6.x'
    
        steps:
        - task: UseDotNet@2
          displayName: 'Use .NET SDK $(dotnetSdkVersion)'
          inputs:
            version: '$(dotnetSdkVersion)'
    
        - task: Npm@1
          displayName: 'Run npm install'
          inputs:
            verbose: false
    
        - script: './node_modules/.bin/node-sass $(wwwrootDir) --output $(wwwrootDir)'
          displayName: 'Compile Sass assets'
    
        - task: gulp@1
          displayName: 'Run gulp tasks'
    
        - script: 'echo "$(Build.DefinitionName), $(Build.BuildId), $(Build.BuildNumber)" > buildinfo.txt'
          displayName: 'Write build info'
          workingDirectory: $(wwwrootDir)
    
        - task: DotNetCoreCLI@2
          displayName: 'Restore project dependencies'
          inputs:
            command: 'restore'
            projects: '**/*.csproj'
    
        - task: DotNetCoreCLI@2
          displayName: 'Build the project - $(buildConfiguration)'
          inputs:
            command: 'build'
            arguments: '--no-restore --configuration $(buildConfiguration)'
            projects: '**/*.csproj'
    
        - task: DotNetCoreCLI@2
          displayName: 'Publish the project - $(buildConfiguration)'
          inputs:
            command: 'publish'
            projects: '**/*.csproj'
            publishWebProjects: false
            arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
            zipAfterPublish: true
    
        - publish: '$(Build.ArtifactStagingDirectory)'
          artifact: drop
    
    - stage: 'Dev'
      displayName: 'Deploy to the dev environment'
      dependsOn: Build
      jobs:
      - deployment: Deploy
        pool:
          vmImage: 'ubuntu-20.04'
        environment: dev
        variables:
        - group: Release
        strategy:
          runOnce:
            deploy:
              steps:
              - download: current
                artifact: drop
              - task: AzureWebApp@1
                displayName: 'Azure App Service Deploy: website'
                inputs:
                  azureSubscription: 'Resource Manager - Tailspin - Space Game'
                  appName: '$(WebAppNameDev)'
                  package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
    
    - stage: 'Test'
      displayName: 'Deploy to the test environment'
      dependsOn: Dev
      jobs:
      - deployment: Deploy
        pool:
          vmImage: 'ubuntu-20.04'
        environment: test
        variables:
        - group: 'Release'
        strategy:
          runOnce:
            deploy:
              steps:
              - download: current
                artifact: drop
              - task: AzureWebApp@1
                displayName: 'Azure App Service Deploy: website'
                inputs:
                  azureSubscription: 'Resource Manager - Tailspin - Space Game'
                  appName: '$(WebAppNameTest)'
                  package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
    
    - stage: 'Staging'
      displayName: 'Deploy to the staging environment'
      dependsOn: Test
      jobs:
      - deployment: Deploy
        pool:
          vmImage: 'ubuntu-20.04'
        environment: staging
        variables:
        - group: 'Release'
        strategy:
          runOnce:
            deploy:
              steps:
              - download: current
                artifact: drop
              - task: AzureWebApp@1
                displayName: 'Azure App Service Deploy: website'
                inputs:
                  azureSubscription: 'Resource Manager - Tailspin - Space Game'
                  appName: '$(WebAppNameStaging)'
                  package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
      - job: RunLoadTests
        dependsOn: Deploy
        displayName: 'Run load tests'
        pool:
          vmImage: 'ubuntu-20.04'
        variables:
        - group: Release
        steps:
        - script: |
            wget -c archive.apache.org/dist/jmeter/binaries/apache-jmeter-$(jmeterVersion).tgz
            tar -xzf apache-jmeter-$(jmeterVersion).tgz
          displayName: 'Install Apache JMeter'
        - script: apache-jmeter-$(jmeterVersion)/bin/./jmeter -n -t LoadTest.jmx -o Results.xml -Jhostname=$(STAGING_HOSTNAME)
          displayName: 'Run Load tests'
        - script: |
            sudo apt-get update
            sudo apt-get install xsltproc
            xsltproc JMeter2JUnit.xsl Results.xml > JUnit.xml
          displayName: 'Transform JMeter output to JUnit'
        - task: PublishTestResults@2
          inputs:
            testResultsFormat: JUnit
            testResultsFiles: JUnit.xml
    

    Ecco un riepilogo delle modifiche:

    • Il processo RunLoadTests esegue il test di carico da un agente Linux.
    • Il processo RunLoadTests dipende dal processo Deploy per assicurare che i processi vengano eseguiti nell'ordine corretto. È necessario distribuire il sito Web nel servizio app prima di poter eseguire i test di carico. Se non si specifica questa dipendenza, i processi all'interno della fase possono essere eseguiti in qualsiasi ordine o in parallelo.
    • La prima attività script scarica e installa JMeter. La variabile della pipeline jmeterVersion specifica la versione di JMeter da installare.
    • La seconda attività script esegue JMeter. L'argomento -J imposta la proprietà hostname in JMeter leggendo la variabile STAGING_HOSTNAME dalla pipeline.
    • La terza attività script installa xsltproc, un processore XSLT e trasforma l'output JMeter in JUnit.
    • L'attività PublishTestResults@2 pubblica il report JUnit risultante, JUnit.xml, nella pipeline. Azure Pipelines può essere utile per visualizzare i risultati del test.
  2. Nel terminale integrato aggiungere azure-pipelines.yml all'indice, eseguire il commit delle modifiche ed eseguire il push del ramo in GitHub.

    git add azure-pipelines.yml
    git commit -m "Run load tests with Apache JMeter"
    git push origin jmeter
    

Osservare l'esecuzione dei test in Azure Pipelines

Qui si può osservare l'esecuzione della pipeline. Si noterà che i test di carico vengono eseguiti durante la fase di staging.

  1. In Azure Pipelines passare alla compilazione e tracciarne l'esecuzione.

    Durante la fase di staging si noterà che i test di carico vengono eseguiti dopo la distribuzione del sito Web.

  2. Al completamento della compilazione, passare alla pagina di riepilogo.

    Screenshot of Azure Pipelines, showing the completed stages.

    Si noterà che la distribuzione e i test di carico sono stati completati correttamente.

  3. Osservare il riepilogo nella parte superiore della pagina.

    Si noterà che l'artefatto della compilazione per il sito Web Space Game viene pubblicato normalmente. Nella sezione Test e code coverage viene anche indicato che i test di carico sono stati superati.

    A screenshot of Azure Pipelines, showing the test summary.

  4. Selezionare il riepilogo dei test per visualizzare il report completo.

    Il report mostra che entrambi i test sono stati superati.

    Screenshot of Azure Pipelines, showing the full test report.

    In caso di esito negativo di un test, verrebbero visualizzati i risultati dettagliati dell'errore. Da questi risultati è possibile analizzare l'origine dell'errore.

    Ricordare che il file XSLT produce un file JUnit denominato JUnit.xml. Il file JUnit risponde a queste due domande:

    • Il tempo medio di richiesta è inferiore a un secondo?
    • Il numero di richieste che hanno impiegato più di un secondo è inferiore al 10%?

    Il report dimostra che questi requisiti sono stati soddisfatti. Per visualizzare maggiori dettagli, selezionare la freccia Risultato nel report. Assicurarsi quindi che sia selezionata solo l'opzione Superato.

    Screenshot of Filtering passed tests in the test report.

    Si noterà che i test case del tempo medio di risposta e del tempo di risposta massimo hanno entrambi esito positivo.

    Screenshot of the test report, showing two successful test cases.

Nota

Si sta usando il piano di servizio app B1, che viene eseguito nel livello Basic. Questo piano è destinato alle app con requisiti di traffico ridotto, ad esempio in un ambiente di test. A causa di questo piano, le prestazioni del sito Web potrebbero essere inferiori al previsto. In pratica, è necessario scegliere un piano per l'ambiente di staging che corrisponda maggiormente all'ambiente di produzione. Ad esempio, i piani Standard e Premium sono destinati ai carichi di lavoro di produzione. Questi piani vengono eseguiti in istanze di macchine virtuali dedicate.