使用 Visual Studio 测试任务并行运行测试

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

运行测试来验证对代码的更改是保持质量的关键。 要使持续集成实践取得成功,必须有一个与每个生成一起运行的良好测试套件。 但是,随着代码库的增长,回归测试套件也趋于增长,运行完整回归测试可能需要很长时间。 有时,测试本身可能会长时间运行 - 如果编写端到端测试,通常就是这种情况。 这降低了交付客户价值的速度,因为管道无法足够快地处理生成。

并行运行测试是提高 CI/CD 管道效率的好方法。 这可以通过采用云提供的额外容量轻松实现。 本文讨论如何配置 Visual Studio 测试任务以使用多个代理并行运行测试。

先决条件

熟悉代理作业的概念。 若要并行运行多个作业,必须配置多个代理。 还需要足够的并行作业

测试切片

Visual Studio 测试任务(版本 2)设计为与并行作业设置无缝配合工作。 包含 Visual Studio 测试任务(为简单起见,称为“VSTest 任务”)的管道作业配置为在多个代理上并行运行时,它会自动检测出涉及了多个代理,并会创建可在这些代理上并行运行的测试切片。

可以将任务配置为创建测试切片以满足不同的要求,例如基于测试和代理数、以前的测试运行时间或程序集内测试的位置进行批处理。

批处理选项

以下部分会说明这些选项。

基于测试和代理数进行简单切片

此设置使用简单切片算法,让“N”个代理分担数量为“T”的测试,以便每个代理运行 T/N 个测试。 例如,如果测试套件包含 1000 个测试,并且你将两个代理用于并行作业,则每个代理将运行 500 个测试。 或者,可以使用 8 个代理进一步减少运行测试所需的时间,在这种情况下,每个代理将并行运行 125 个测试。

通常会在所有测试的运行时间都相似时使用此选项。 如果测试运行时间不相似,则可能无法有效利用代理,因为某些代理可能会接收具有多个长时间运行的测试的切片,而其他代理可能会接收具有运行时间较短的测试的切片,并且会大大早于其余代理完成。

基于过去的测试运行时间进行切片

此设置考虑过去的运行时间来创建测试切片,以便每个切片的运行时间都大致相同。 短时间运行的测试将一起批处理,而长时间运行的测试将分配到单独的切片。

当程序集内的测试没有依赖项并且不需要在同一代理上运行时,应使用此选项。 此选项可最有效地利用代理,因为每个代理将获得相同的“工作”量,并且几乎都在同一时间完成。

基于测试程序集进行切片

此设置使用简单切片算法,让“N”个代理分担数量为“A”的测试程序集(或文件),以便每个代理运行 A/N 个程序集内的测试。 使用此选项时,不会考虑程序集内的测试数。 例如,如果测试套件包含十个测试程序集,并且你对并行作业使用两个代理,则每个代理将收到五个要运行的测试程序集。 可以使用五个代理进一步减少运行测试所需的时间,在这种情况下,每个代理将获得要运行的两个测试程序集。

当程序集内的测试具有依赖项或利用 AssemblyInitializeAssemblyCleanupClassInitializeClassCleanup 方法来管理测试代码中的状态时,应使用此选项。

在经典生成管道中并行运行测试

如果要在经典生成管道中运行大型测试套件或长时间运行的集成测试,请使用以下步骤。

注意

若要在带有本地 TFS 服务器的生成管道中使用多代理功能,必须使用 TFS 2018 Update 2 或更高版本。

  1. 使用单个代理生成作业。 使用下图所示的任务生成 Visual Studio 项目并发布生成工件。 这将使用默认作业设置(单一代理,无并行作业)。

    buildJobSingleAgent

  2. 使用多个代理并行运行测试

    • 添加代理作业

      AddAgentJobBuild

    • 将作业配置为并行使用多个代理。 此处的示例使用三个代理。

      ParallelTestJobBuild

      提示

      对于大规模并行测试,可以指定多达 99 个的代理。

    • 将“下载生成工件”任务添加到作业。 此步骤是生成作业与测试作业之间的链接,是确保生成作业中产生的二进制文件在测试作业用于运行测试的代理上可用所必需的。 确保任务设置为下载由“当前生成”产生的工件,并且工件名称与生成作业中的“发布生成工件”任务内使用的工件名称相同。

      DownloadBuildArtifacts

    • 添加“Visual Studio 测试”任务并将其配置为使用所需的切片策略

在 YAML 管道中设置作业以进行并行测试

job 中指定 parallel 策略,并指出应分派多少个作业。 最多可指定 99 个代理来为大型测试套件纵向扩展测试。

jobs:
- job: ParallelTesting
  strategy:
    parallel: 2

有关详细信息,请参阅 YAML 架构 - 作业

在经典发布管道中并行运行测试

如果在部署应用程序后要运行大型测试套件或长时间运行的功能测试,请使用以下步骤。 例如,你可能想要部署 Web 应用程序并在浏览器中运行 Selenium 测试,以验证应用功能。

注意

若要在带有本地 TFS 服务器的发布管道中使用多代理功能,必须使用 TFS 2017 Update 1 或更高版本。

  1. 使用单个代理部署应用。 使用 Azure 部署:创建或更新资源组或 Azure 应用服务部署任务,将 Web 应用部署到 Azure 应用服务。 这将使用默认作业设置(单一代理,无并行作业)。

    DeployApp1Agent

  2. 使用多个代理并行运行测试

    • 添加代理作业

      AddAgentJobRM

    • 将作业配置为并行使用多个代理。 此处的示例使用三个代理。

      ParallelTestJobRM

      提示

      对于大规模并行测试,可以指定多达 99 个的代理。

    • 添加在运行 Visual Studio 测试任务之前必须运行的任何其他任务。 例如,运行 PowerShell 脚本以设置测试所需的任何数据。

      提示

      默认情况下,发布管道中的作业会下载链接到发布管道的所有工件。 为了节省时间,可以将作业配置为仅下载作业所需的测试工件。 例如,Web 应用二进制文件对运行 Selenium 测试而言并非必需,如果你的生成管道分别发布应用和测试工件,则可以跳过下载这些二进制文件。

    • 添加“Visual Studio 测试”任务并将其配置为使用所需的切片策略

      提示

      如果测试计算机未安装 Visual Studio,可以使用 Visual Studio 测试平台安装程序任务来获取所需版本的测试平台。

通过将并行管道作业与并行测试执行相结合进行大规模并行测试

在管道中使用并行作业时,它会使用多个计算机(代理)并行运行每个作业。 测试框架和运行程序还提供在单个计算机上并行运行测试(通常是通过创建并行运行的多个进程或线程)的功能。 可以采用分层方式组合并行功能,以实现大规模并行测试。 在 Visual Studio 测试任务的上下文中,可以通过以下方式组合并行:

  1. 测试框架提供的并行。 MSTest v2、NUnit、xUnit 等所有新式测试框架都提供并行运行测试的功能。 通常,程序集内的测试是并行运行的。 这些测试框架使用测试适配器和测试框架以及相应的适配器与 Visual Studio 测试平台进行交互,并在运行测试时在 Visual Studio 测试平台创建的测试主机进程内工作。 因此,此层的并行化是在一个用于所有框架和适配器的进程中进行的。

  2. Visual Studio 测试平台 (vstest.console.exe) 提供的并行。 Visual Studio 测试平台可以并行运行测试程序集。 vstest.console.exe 的用户会将此功能识别为 /parallel 开关。 它通过在每个可用核心上启动一个测试主机进程,并将其传递给要执行的程序集内的测试来实现这一点。 这适用于具有 Visual Studio 测试平台测试适配器的任何框架,因为并行化单元是一个测试程序集或测试文件。 在与测试框架提供的并行(如上所述)相结合的情况下,这会在测试运行于管道中的单个代理上时提供最大程度的并行化。

  3. Visual Studio 测试 (VSTest) 任务提供的并行。 VSTest 任务支持跨多个代理(或计算机)并行运行测试。 测试切片将被创建,并且每个代理一次执行一个切片。 三种不同的切片策略在与测试平台和测试框架提供的并行(如上所述)相结合时,将产生以下结果:

    • 基于测试和代理数进行切片。 简单切片,其中测试分组到大小相等的切片中。 一个切片包含来自一个或多个程序集的测试。 因此,代理上的测试执行将符合上述 1 和 2 中所述的并行。

    • 基于过去的运行时间进行切片。 根据之前运行测试的计时和可用代理的数量,测试被分组到切片中,使得每个切片需要大致相等的执行时间。 一个切片包含来自一个或多个程序集的测试。 因此,代理上的测试执行将符合上述 1 和 2 中所述的并行。

    • 基于程序集进行切片。 一个切片是一个测试程序集,并且因此包含所有属于同一程序集的测试。 因此,代理上的执行将符合上述 1 和 2 中所述的并行。 但是,如果代理只收到一个要运行的程序集,则可能不会发生 2。

帮助和支持