練習 - 在 Azure Pipelines 中執行負載測試

已完成

在本節中,您會執行您在發行管線中建立的測試計劃。 測試計劃會使用 Apache JMeter 來執行負載測試。

以下是執行測試的方式:

  • 擷取並簽出一個實作測試的 Git 分支。
  • 修改您的管線以安裝 JMeter、執行測試計劃、將結果轉換成 JUnit,然後將結果發佈至 Azure Pipelines。
  • 將您的分支推送至 GitHub、監看 Azure Pipelines 中執行的測試,然後檢查結果。

從 GitHub 擷取分支

在本節中,您會從 GitHub 擷取 jmeter 分支,並簽出或切換至該分支。

此分支包含您在先前課程模組中使用的 Space Game 專案。 其也包含可供開始使用的 Azure Pipelines 設定。

  1. 在 Visual Studio Code 中,開啟整合式終端。

  2. 執行下列 git fetchgit checkout 命令,以從 Microsoft 的存放庫下載名為 jmeter 的分支,並切換至該分支:

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

    請回想一下,upstream 指的是 Microsoft GitHub 存放庫。 您專案的 Git 設定可辨識上游遠端存放庫,因為當您從 Microsoft 的存放庫派生專案並在本機加以複製時,便已為其設定了關聯性。

    不久後,您就會將此分支推送至自己的 GitHub 存放庫,名為 origin

  3. 在 Visual Studio Code 中,可以選擇性地開啟 azure-pipelines.yml 檔案。 檢閱初始設定。

    該設定類似於您在此學習路徑的先前課程模組中所建立的設定。 其只會建置應用程式的發行設定。 為了簡潔起見,它會省略您在先前課程模組中設定的觸發程序、手動核准與測試。

    注意

    更健全的設定可能會指定參與組建流程的分支。 例如,為協助驗證程式碼品質,您可以在每次在任何分支上推送變更時執行單元測試。 您也可以將應用程式部署到執行更詳盡測試的環境。 但是,只有當您有提取要求、有候選版,或將程式碼合併到 main 時,才會進行此部署。

    如需詳細資訊,請參閱使用 Git 和 GitHub 在組建管線實作程式碼流程組建管線觸發程序

  4. 在 Visual Studio Code 中,您可以選擇性地簽出 JMeter 測試計劃檔案 (LoadTest) 和 XLST 轉換 (JMeter2JUnit.xsl)。 XLST 檔案會將 JMeter 輸出轉換為 JUnit,讓 Azure Pipelines 可以將結果視覺化。

將變數新增至 Azure Pipelines

小組的原始測試計劃為在預備環境中所執行 Space Game 網站的主機名稱,提供硬式編碼的值。

為了讓測試計劃更有彈性,您的版本會使用 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. 選取 [發行] 變數群組。

  4. 在 [變數] 下,選取 [+ 新增]

  5. 針對您的變數名稱,輸入 STAGING_HOSTNAME。 針對其值,輸入 App Service 執行個體的 URL,此 URL 對應至您的預備環境,例如 tailspin-space-game-web-staging-1234.azurewebsites.net

    重要

    請不要在您的值中包含 http://https:// 通訊協定首碼。 JMeter 會在測試執行時提供通訊協定。

  6. 新增名為 jmeterVersion 的第二個變數。 針對其值,指定 5.4.3

    注意

    這是我們上次用來測試此課程模組的 JMeter 版本。 若要取得最新版本,請參閱下載 Apache JMeter (英文)。

  7. 若要將您的變數儲存至管線,請選取頁面頂端附近的 [儲存]

    您的變數群組類似於下圖所示的群組:

    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 作業,以確保這些作業是以正確順序執行。 您必須先將網站部署到 App Service,然後才能執行負載測試。 如果您未指定此相依性,階段內的作業可以依任何順序執行或平行執行。
    • 第一個 script 工作會下載並安裝 JMeter。 jmeterVersion 管線變數會指定要安裝的 JMeter 版本。
    • 第二個 script 工作會執行 JMeter。 -J 引數會透過從管線讀取 STAGING_HOSTNAME 變數來設定 JMeter 中的 hostname 屬性。
    • 第三個 script 工作會安裝 xsltproc (一個 XSLT 處理器),並將 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 中,移至組建並在該組建執行時加以追蹤。

    在「預備」期間,您會在網站完成部署之後看到負載測試執行。

  2. 建置完成後,請移至摘要頁面。

    Screenshot of Azure Pipelines, showing the completed stages.

    您會看到部署和負載測試順利完成。

  3. 請注意頁面頂端附近的摘要。

    您會看到 Space Game 網站的組建成品與往常一樣進行發佈。 亦請注意 [測試和涵蓋範圍] 區段,其中顯示負載測試已通過。

    A screenshot of Azure Pipelines, showing the test summary.

  4. 選取測試摘要來查看完整的報告。

    報告顯示這兩個測試都已通過。

    Screenshot of Azure Pipelines, showing the full test report.

    如果有任何測試失敗,您會看到失敗的詳細結果。 您可以從這些結果調查失敗的來源。

    回想一下,XSLT 檔案會產生名為 JUnit.xml 的 JUnit 檔案。 JUnit 檔案回答下列兩個問題:

    • 平均要求時間小於一秒嗎?
    • 少於 10% 的要求需要一秒以上的時間才能完成嗎?

    此報告證明符合這些需求。 若要查看更多詳細資料,請選取報告中的 [結果] 箭號。 然後,確定只選取 [已通過]

    Screenshot of Filtering passed tests in the test report.

    您會看到 [平均回應時間] 和 [最大回應時間] 測試案例都成功。

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

注意

您使用的是 B1 App Service 方案,其會在基本層上執行。 此方案適用於具有低流量需求的應用程式,例如測試環境中的應用程式。 由於此方案,您的網站效能可能會比您預期的還要低。 實務上,您會針對更密切符合您生產環境的預備環境選擇一個方案。 例如,標準進階方案適用於生產工作負載。 這些方案會在專用的虛擬機器執行個體上執行。