演習 - Azure Pipelines でロード テストを実行する

完了

このセクションでは、リリース パイプラインに作成したテスト計画を実行します。 テスト計画では、Apache JMeter を使用してロード テストを実行します。

テストの実行方法を次に示します。

  • テストを実装する Git ブランチをフェッチしてチェックアウトします。
  • JMeter をインストールし、テスト計画を実行し、結果を JUnit に変換し、結果を Azure Pipelines に発行するようにパイプラインを変更します。
  • ブランチを GitHub にプッシュし、Azure Pipelines で実行されているテストを監視し、結果を確認します。

GitHub からブランチをフェッチする

このセクションでは、GitHub から jmeter ブランチをフェッチし、そのブランチをチェックアウトします (つまりそのブランチに切り替えます)。

このブランチには、前のモジュールで作業した Space Game プロジェクトが含まれています。 また、最初に使用する Azure Pipelines 構成も含まれています。

  1. Visual Studio Code で、統合ターミナルを開きます。

  2. Microsoft のリポジトリから jmeter という名前のブランチをダウンロードし、そのブランチに切り替えるために、次の git fetch および git checkout コマンドを実行します。

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

    upstream とは Microsoft GitHub リポジトリを指していることを思い出してください。 Microsoft のリポジトリからプロジェクトをフォークしてローカルにクローンしたときにアップストリーム リモートの関係をセットアップしたので、プロジェクトの Git 構成ではそれが認識されます。

    すぐに、origin と呼ばれる独自の GitHub リポジトリにこのブランチをプッシュします。

  3. 必要に応じて、Visual Studio Code で、azure-pipelines.yml ファイルを開きます。 その初期構成を確認します。

    この構成は、このラーニング パスの前のモジュールで作成したものに似ています。 これによって、アプリケーションのリリース構成のみがビルドされます。 簡潔さのために、以前のモジュールで設定したトリガー、手動の承認、テストは省略されています。

    Note

    より堅牢な構成では、ビルド プロセスに参加するブランチを指定できます。 たとえば、コードの品質を検証するために、いずれかのブランチに変更をプッシュするたびに、単体テストを実行できます。 さらに包括的なテストを実行する環境にアプリケーションをデプロイすることもできます。 ただし、このデプロイは、pull request がある場合、リリース候補がある場合、またはコードを main にマージする場合にのみ実行します。

    詳細については、Git と GitHub を使用したビルド パイプラインでのコード ワークフローの実装に関するモジュール、およびビルド パイプラインのトリガーに関するページを参照してください。

  4. 必要に応じて、Visual Studio Code で、JMeter テスト計画ファイル LoadTest、および XLST 変換 JMeter2JUnit.xsl をチェックアウトできます。 XLST ファイルは、Azure Pipelines で結果を視覚化できるように、JMeter 出力を JUnit に変換します。

変数を Azure Pipelines に追加する

チームの元のテスト計画では、ステージング環境で実行される Space Game Web サイトのホスト名にハードコーディングされた値が提供されています。

テスト計画の柔軟性を高めるために、こちらのバージョンでは JMeter プロパティを使用しています。 プロパティは、コマンド ラインから設定できる変数と考えてください。

JMeter で hostname 変数が定義される方法を次に示します。

Screenshot of setting the hostname variable in Apache JMeter.

hostname 変数が __P 関数を使用して hostname 変数を読み取る方法を次に示します。

Screenshot for reading the hostname variable in Apache JMeter.

対応するテスト計画ファイル LoadTest.jmx でこの変数が指定されており、それを使ってホスト名を設定します。

コマンド ラインから JMeter を実行する場合は、-J 引数を使用して hostname プロパティを設定します。 次に例を示します。

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

ここでは、Azure Pipelines に STAGING_HOSTNAME 変数を設定します。 この変数は、ステージング環境内の App Service で実行されているサイトのホスト名を指します。 また、jmeterVersion を設定して、インストールする JMeter のバージョンを指定します。

エージェントを実行すると、これらの変数は環境変数としてエージェントに自動的にエクスポートされます。そのため、パイプラインの構成では、次のように JMeter を実行できます。

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

パイプラインの構成を更新する前に、ここでパイプラインの変数を追加しましょう。 そのためには次を行います。

  1. Azure DevOps で、Space Game - web - Nonfunctional tests プロジェクトにアクセスします。

  2. [パイプライン][ライブラリ] を選択します。

  3. [Release] 変数グループを選択します。

  4. [Variables] で、[+ Add] を選択します。

  5. 変数の名前として「STAGING_HOSTNAME」と入力します。 値として、ステージング環境に対応する App Service インスタンスの URL (tailspin-space-game-web-staging-1234.azurewebsites.net など) を入力します。

    重要

    値には http:// または https:// プロトコル プレフィックスを含めないでください。 テストの実行時に、JMeter によってプロトコルが提供されます。

  6. jmeterVersion という名前の 2 つ目の変数を追加します。 その値として、5.4.3 を指定します。

    Note

    これは、このモジュールをテストするために最後に使用した JMeter のバージョンです。 最新バージョンを入手するには、Apache JMeter のダウンロードに関するページを参照してください。

  7. ページの上部付近で、変数をパイプラインに保存するために、[Save] を選びます。

    変数グループは、次の図で示されているようになります。

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

パイプライン構成を変更する

このセクションでは、"ステージング" 段階中にロード テストを実行するようにパイプラインを変更します。

  1. Visual Studio Code で、azure-pipelines.yml ファイルを開きます。 次に、以下のようにファイルを変更します。

    ヒント

    ファイル全体を置き換えることも、強調表示されている部分のみを更新することもできます。

    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
    

    変更の概要を次に示します。

    • RunLoadTests ジョブは、Linux エージェントからロード テストを行います。
    • RunLoadTests ジョブは Deploy ジョブに依存して、ジョブが正しい順序で実行されるようにします。 ロード テストを実行する前に、Web サイトを App Service にデプロイする必要があります。 この依存関係を指定しない場合は、ステージ内のジョブを任意の順序で実行することも、並列で実行することもできます。
    • 最初の script タスクは、JMeter をダウンロードしてインストールします。 jmeterVersion パイプライン変数では、インストールする JMeter のバージョンを指定します。
    • 2 番目の script タスクは、JMeter を実行します。 -J 引数は、パイプラインから STAGING_HOSTNAME 変数を読み取って、JMeter 内の hostname プロパティを設定します。
    • 3 番目の script タスクは、XSLT プロセッサである xsltproc をインストールし、JMeter 出力を JUnit に変換します。
    • PublishTestResults@2 タスクは、結果として生成された JUnit レポートである JUnit.xml をパイプラインに発行します。 Azure Pipelines は、テスト結果を視覚化するのに役立ちます。
  2. 統合ターミナルで、azure-pipelines.yml をインデックスに追加し、変更をコミットして、GitHub にブランチをプッシュします。

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

Azure Pipelines でのテストの実行を監視する

ここでは、パイプラインの実行を監視します。 ロード テストが "ステージング" 中に実行されていることがわかります。

  1. Azure Pipelines で、ビルドに移動し、実行中にそれをトレースします。

    "ステージング" 中、Web サイトのデプロイ後にロード・テストが実行されていることがわかります。

  2. ビルドが完了したら、概要ページに移動します。

    Screenshot of Azure Pipelines, showing the completed stages.

    デプロイとロード テストが正常に完了したことがわかります。

  3. ページの上部近くにある概要を確認します。

    Space Game Web サイトのビルド成果物が、いつものように発行されていることがわかります。 また、ロード テストが成功したことを示している [テストとカバレッジ] セクションにも注意してください。

    A screenshot of Azure Pipelines, showing the test summary.

  4. テストの概要を選択して、完全なレポートを表示します。

    レポートには、両方のテストが成功したことが示されています。

    Screenshot of Azure Pipelines, showing the full test report.

    テストが失敗した場合は、エラーの詳細な結果が表示されます。 これらの結果から、エラーの原因を調査できます。

    XSLT ファイルによって JUnit.xml という JUnit ファイルが生成されることを思い出してください。 JUnit ファイルでは、次の 2 つの質問に回答します。

    • 平均要求時間は 1 秒未満か。
    • 完了までにかかる時間が 1 秒を超えるのは、要求の 10% 未満か。

    このレポートでは、これらの要件が満たされていることが証明されます。 詳細を表示するには、レポートにある [Outcome](結果) の矢印を選択します。 次に、[Passed](合格) のみが選択されていることを確認します。

    Screenshot of Filtering passed tests in the test report.

    [平均応答時間][最大応答時間] テスト ケースが両方とも成功だったことがわかります。

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

Note

Basic レベルで実行される B1 App Service プランを使用しています。 このプランは、テスト環境のアプリなど、トラフィック要件が低いアプリを対象としています。 このプランのため、Web サイトのパフォーマンスは予想よりも低くなる可能性があります。 実際には、運用環境により近いステージング環境用の計画を選びます。 たとえば、Standard および Premium プランは、運用環境のワークロードに適しています。 これらは、専用の仮想マシン インスタンスで実行されます。