Exercice - Effectuer des tests de charge dans Azure Pipelines

Effectué

Dans cette section, vous allez exécuter le plan de test que vous avez créé dans le pipeline de mise en production. Le plan de test utilise Apache JMeter pour effectuer des tests de charge.

Voici comment vous effectuez les tests :

  • Récupérez et extrayez une branche Git qui implémente les tests.
  • Modifiez votre pipeline pour installer JMeter, exécutez le plan de test, transformez les résultats en JUnit et publiez les résultats sur Azure Pipelines.
  • Poussez votre branche vers GitHub, observez les tests exécutés dans Azure Pipelines, puis examinez les résultats.

Récupérer (fetch) la branche à partir de GitHub

Dans cette section, vous allez récupérer la branche jmeter à partir de GitHub pour l’extraire ou pour passer à celle-ci.

Cette branche contient le projet Space Game que vous avez utilisé dans les modules précédents. Elle contient également une configuration Azure Pipelines qui vous permet de démarrer.

  1. Dans Visual Studio Code, ouvrez le terminal intégré.

  2. Pour télécharger une branche nommée jmeter à partir du dépôt Microsoft, passez à cette branche, puis exécutez les commandes git fetch et git checkout suivantes :

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

    Rappelez-vous que upstream (amont) fait référence au dépôt GitHub Microsoft. La configuration Git de votre projet comprend le dépôt distant upstream (amont), car vous avez configuré cette relation quand vous avez dupliqué le projet à partir du dépôt de Microsoft et que vous l’avez cloné localement.

    Dans quelques instants, vous pousserez (push) cette branche vers votre dépôt GitHub appelé origin.

  3. Si vous le souhaitez, dans Visual Studio Code, ouvrez le fichier azure-pipelines.yml. Examinez la configuration initiale.

    La configuration ressemble à celles que vous avez créées dans les modules précédents de ce parcours d’apprentissage. Elle crée seulement la configuration Production de l’application. Par souci de concision, la configuration omet les déclencheurs, les approbations manuelles et les tests que vous avez configurés dans les modules précédents.

    Notes

    Pour une configuration plus robuste, les branches qui participent au processus de génération pourraient être spécifiées. Par exemple, pour faciliter la vérification de la qualité du code, vous pouvez effectuer des tests unitaires chaque fois que vous poussez une modification dans une branche. Vous pouvez aussi déployer l’application sur un environnement qui effectue des tests plus exhaustifs. Toutefois, vous ne procédez à ce déploiement que lorsque vous avez une requête de tirage (pull request), lorsque vous disposez d'une version Release Candidate, ou lorsque vous fusionnez du code sur la base de type primaire.

    Pour plus d’informations, consultez Implémenter un workflow de code dans votre pipeline de build à l’aide de Git et GitHub et Déclencheurs de pipeline de build.

  4. Si vous le souhaitez, dans Visual Studio Code, vous pouvez extraire le fichier de plan de test JMeter, LoadTest.jmx, et la transformation XSLT, JMeter2JUnit.xsl. Le fichier XSLT transforme la sortie JMeter en JUnit afin qu’Azure Pipelines puisse visualiser les résultats.

Ajouter des variables à Azure Pipelines

Le plan de test d’origine de l’équipe fournit une valeur codée en dur pour le nom d’hôte du site web Space Game qui s’exécute dans l’environnement intermédiaire.

Pour rendre le plan de test plus flexible, votre version utilise une propriété JMeter. Vous pouvez considérer une propriété comme une variable que vous pouvez définir à partir de la ligne de commande.

Voici comment la variable hostname est définie dans JMeter :

Screenshot of setting the hostname variable in Apache JMeter.

Voici comment la variable hostname utilise la fonction __P pour lire la variable hostname.

Screenshot for reading the hostname variable in Apache JMeter.

Le fichier de plan de test correspondant, LoadTest.jmx, spécifie cette variable et l’utilise pour définir le nom d’hôte.

Quand vous exécutez JMeter à partir de la ligne de commande, vous utilisez l’argument -J pour définir la propriété hostname. Voici un exemple :

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

Ici, vous définissez la variable STAGING_HOSTNAME dans Azure Pipelines. Cette variable pointe vers le nom d’hôte de votre site qui s’exécute sur App Service dans votre environnement de préproduction. Vous définissez aussi jmeterVersion pour spécifier la version de JMeter à installer.

Quand l’agent s’exécute, ces variables sont exportées automatiquement vers l’agent en tant que variables d’environnement afin que la configuration de votre pipeline puisse exécuter JMeter de cette façon :

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

Nous allons maintenant ajouter les variables de pipeline avant de mettre à jour la configuration de votre pipeline. Pour ce faire :

  1. Dans Azure DevOps, accédez à votre projet Space Game - web - Nonfunctional tests.

  2. Sous Pipelines, sélectionnez Bibliothèques.

  3. Sélectionnez le groupe de variables Release.

  4. Sous Variables, sélectionnez + Ajouter.

  5. Pour le nom de votre variable, entrez STAGING_HOSTNAME. Comme valeur, entrez l’URL de l’instance App Service qui correspond à votre environnement de préproduction, par exemple tailspin-space-game-web-staging-1234.azurewebsites.net.

    Important

    N’incluez pas le préfixe de protocole http:// ou https:// dans votre valeur. JMeter fournit le protocole lors de l’exécution des tests.

  6. Ajoutez une deuxième variable nommée jmeterVersion. Pour sa valeur, spécifiez 5.4.3.

    Notes

    Il s’agit de la version de JMeter que nous avons utilisée pour tester ce module. Pour obtenir la version la plus récente, consultez Télécharger Apache JMeter.

  7. Sélectionnez Enregistrer en haut de la page pour enregistrer votre variable dans le pipeline.

    Votre groupe de variables ressemble à celui montré dans l’image suivante :

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

Modifier la configuration du pipeline

Dans cette section, vous modifierez le pipeline pour exécuter vos tests de charge pendant l’étape Mise en lots.

  1. Dans Visual Studio Code, ouvrez le fichier azure-pipelines.yml. Ensuite, modifiez le fichier comme suit :

    Conseil

    Vous pouvez remplacer le fichier entier ou simplement mettre à jour la partie mise en surbrillance.

    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
    

    Voici un résumé de ces modifications :

    • Le travail RunLoadTests effectue des tests de charge à partir d’un agent Linux.
    • Le travail RunLoadTests dépend du travail Deploy pour garantir que les travaux s’exécutent dans le bon ordre. Vous devez déployer le site web sur App Service avant de pouvoir exécuter les tests de charge. Si vous ne spécifiez pas cette dépendance, les travaux de cette phase peuvent s’exécuter dans n’importe quel ordre ou en parallèle.
    • La première tâche du script télécharge et installe JMeter. La variable de pipeline jmeterVersion spécifie la version de JMeter à installer.
    • La deuxième tâche du script exécute JMeter. L’argument -J définit la propriété hostname dans JMeter en lisant la variable STAGING_HOSTNAME à partir du pipeline.
    • La troisième tâche du script installe xsltproc, un processeur XSLT, et transforme la sortie JMeter en JUnit.
    • La tâche PublishTestResults@2 publie le rapport JUnit résultant, JUnit.xml, sur le pipeline. Azure Pipelines peut vous aider à visualiser les résultats des tests.
  2. Dans le terminal intégré, ajoutez azure-pipelines.yml à l’index, commitez les modifications, puis poussez la branche sur GitHub.

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

Regarder Azure Pipelines exécuter les tests

Ici, vous observerez l’exécution du pipeline. Vous verrez l’exécution des tests de charge dans la phase Mise en lots.

  1. Dans Azure Pipelines, accédez à la build et effectuez son suivi lors de son exécution.

    Pendant la phase Préproduction, vous voyez que les tests de charge s’exécutent après le déploiement du site web.

  2. Une fois la build terminée, accédez à la page récapitulative.

    Screenshot of Azure Pipelines, showing the completed stages.

    Vous voyez que le déploiement et les tests de charge se sont terminés avec succès.

  3. Dans la partie supérieure de la page, notez le récapitulatif.

    Vous voyez que l’artefact de build pour le site web Space Game est publié comme toujours. Notez également la section Tests and coverage qui indique que les tests de charge ont réussi.

    A screenshot of Azure Pipelines, showing the test summary.

  4. Sélectionnez le récapitulatif des tests pour voir le rapport complet.

    Le rapport indique que les deux tests ont réussi.

    Screenshot of Azure Pipelines, showing the full test report.

    Si un test a échoué, vous verrez les résultats détaillés de l’échec. À partir de ces résultats, vous pouvez rechercher la source de l’échec.

    Rappelez-vous que le fichier XSLT produit un fichier JUnit, nommé JUnit.xml. Le fichier JUnit répond à ces deux questions :

    • La durée moyenne d’une requête est-elle inférieure à une seconde ?
    • Moins de 10 % des requêtes ont-elles une durée supérieure à une seconde ?

    Le rapport prouve que ces exigences sont satisfaites. Pour voir plus de détails, sélectionnez la flèche Outcome dans le rapport. Vérifiez ensuite que seule l’option Passed est sélectionnée.

    Screenshot of Filtering passed tests in the test report.

    Vous constatez que les deux cas de test Temps de réponse moyen et Temps de réponse maximal ont réussi.

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

Remarque

Vous utilisez le plan App Service B1, qui s’exécute sur le niveau De base. Ce plan est conçu pour les applications qui ont des exigences de trafic faibles, comme des applications dans un environnement de test. En raison de ce plan, les performances de votre site web peuvent être inférieures à celles que vous attendez. Dans la pratique, vous devez choisir un plan pour l’environnement intermédiaire qui correspond le plus à votre environnement de production. Par exemple, les plans Standard et Premium sont destinés aux charges de travail de production. Ils s’exécutent sur des instances de machine virtuelle dédiées.