练习 - 在 Azure Pipelines 中运行负载测试
在本部分中,你将在发布管道中运行你创建的测试计划。 测试计划使用 Apache JMeter 来运行负载测试。
下面是运行测试的方式:
- 提取并签出实现测试的 Git 分支。
- 修改管道以安装 JMeter,运行测试计划,将结果转换为 JUnit,然后将结果发布到 Azure Pipelines。
- 将分支推送到 GitHub,查看 Azure Pipelines 中运行的测试,然后检查结果。
从 GitHub 中提取分支
在本部分中,你将从 GitHub 提取 jmeter
分支,签出或切换到该分支。
该分支包含在之前的模块中使用过的 Space Game 项目。 它还包含要从其开始的 Azure Pipelines 配置。
在 Visual Studio Code 中打开集成终端。
要从 Microsoft 的存储库中下载名为
jmeter
的分支,并切换到该分支,请运行以下git fetch
和git checkout
命令:git fetch upstream jmeter git checkout -B jmeter upstream/jmeter
回想一下,“upstream”指的是 Microsoft GitHub 存储库。 项目的 Git 配置能够识别 upstream 远程库,因为当你从 Microsoft 的存储库中创建该项目的分支并在本地克隆它时,就建立了这种关系。
稍后,你会将此分支推送到 GitHub 存储库(称作
origin
)。(可选)在 Visual Studio Code 中,打开 azure-pipelines.yml 文件。 检查初始配置。
该配置类似于在此学习路径前面的模块中创建的配置。 它只生成应用程序的发布配置。 为了简洁起见,它省略了在之前的模块中设置的触发器、手动审批和测试。
备注
可以使用更可靠的配置来指定参与生成过程的分支。 例如,为了帮助验证代码质量,你可以在每次对任何分支推送更改时运行单元测试。 你还可以将应用程序部署到执行更全面测试的环境。 但仅当你有拉取请求、候选发布或将代码合并到主分支时,才能执行此部署。
有关详细信息,请参阅使用 Git 和 GitHub 在生成管道中实现代码工作流和生成管道触发器。
(可选)在 Visual Studio Code 中,可签出 JMeter 测试计划文件 (LoadTest.jmx) 和 XLST 转换 (JMeter2JUnit.xsl)。 XLST 文件将 JMeter 输出转换为 JUnit,以便 Azure Pipelines 可以可视化结果。
将变量添加到 Azure Pipelines
团队的原始测试计划为在“过渡”环境中运行的 Space Game 网站的主机名提供硬编码值。
为了使测试计划更灵活,你的版本会使用 JMeter 属性。 将属性视为可从命令行设置的变量。
下面是 hostname
变量在 JMeter 中的定义方式:
下面是 hostname
变量使用 函数读取 hostname
变量的方式。
对应的测试计划文件 (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
变量。 此变量指向“过渡”环境中在应用服务上运行的站点的主机名。 还可将 jmeterVersion
设置为指定要安装的 JMeter 的版本。
代理运行时,这些变量将作为环境变量自动导出到代理,因此,你的管道配置可通过以下方式运行 JMeter:
apache-jmeter-5.4.3/bin/./jmeter -n -t LoadTest.jmx -o Results.xml -Jhostname=$(STAGING_HOSTNAME)
在更新管道配置之前,先添加管道变量。 为此,请执行以下操作:
在 Azure DevOps 中,转到“Space Game - web - Nonfunctional tests”项目。
在“Pipelines”下,选择“Library”。
选择“发布”变量组。
在“Variables”下,选择“+ Add”。
输入 STAGING_HOSTNAME 作为变量名称。 输入与“过渡”环境相对应的应用服务实例的 URL(如 tailspin-space-game-web-staging-1234.azurewebsites.net)作为它的值。
重要
值中不要包含
http://
或https://
协议前缀。 JMeter 在测试运行时提供协议。添加另一个名为 jmeterVersion 的变量。 指定 5.4.3 作为它的值。
备注
这是上次用于测试此模块的 JMeter 版本。 获取最新版本,请参阅下载 Apache JMeter。
在页面顶部附近选择“保存”,将变量保存到管道中。
变量组如下图所示:
修改管道配置
在本部分中,你将管道修改为能够在“过渡”阶段运行负载测试。
在 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
作业,以确保作业按正确的顺序运行。 在运行负载测试之前,需要将网站部署到应用服务。 如果未指定此依赖项,阶段中的作业可以按任何顺序运行,也可以并行运行。- 第一个
script
任务下载并安装 JMeter。jmeterVersion
管道变量指定要安装的 JMeter 版本。 - 第二个
script
任务运行 JMeter。-J
参数通过从管道中读取STAGING_HOSTNAME
变量来设置 JMeter 中的hostname
属性。 - 第三个
script
任务安装 xsltproc(一种 XSLT 处理器),并将 JMeter 输出转换为 JUnit。 PublishTestResults@2
任务将生成的 JUnit 报告 (JUnit.xml) 发布到管道。 Azure Pipelines 可帮助可视化测试结果。
在集成终端中,将 azure-pipelines.yml 添加到索引,提交更改,然后将分支推送到 GitHub。
git add azure-pipelines.yml git commit -m "Run load tests with Apache JMeter" git push origin jmeter
观察 Azure Pipelines 运行测试
现在,你将观察管道运行。 你会看到负载测试在“过渡”阶段运行。
在 Azure Pipelines 中,转到生成并在运行时对其进行跟踪。
在“过渡”阶段,可看见负载测试在网站部署后运行。
生成完成后,转到摘要页。
可看到已成功完成部署和负载测试。
在页面顶部附近,注意摘要。
可看到 Space Game 网站的生成工件像往常一样发布。 另请注意“Tests and coverage”部分,其中显示负载测试已通过。
选择“测试摘要”以查看完整的报告。
此报告显示两个测试均已通过。
如果有任何测试失败,你都会看到失败的详细结果。 根据这些结果可调查失败的根源。
回想一下,XSLT 文件会生成一个名为 JUnit.xml 的 JUnit 文件。 JUnit 文件可解答以下两个问题:
- 平均请求时间是否少于一秒?
- 是否有不到 10% 的请求时间会超过一秒?
此报告证明满足了这些要求。 在报告中选择“Outcome”箭头了解更多信息。 然后确保仅选中“Passed”。
可看到“Average Response Time”和“Max Response Time”这两种测试用例均已成功。
注意
你使用的是在基本层上运行的 B1 应用服务计划。 此计划适用于流量需求较低的应用,如测试环境中的应用。 而由于该计划,你的网站性能可能会低于预期。 实际操作时,可以选择一个与生产环境更匹配的适用于“过渡”环境的计划。 例如,“标准”计划和“高级”计划适用于生产工作负载。 这些计划在专用虚拟机实例上运行。