You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Azure DevOps .NET SDK克隆含测试套件的Test Plan?

解决Azure DevOps Server 2020.1.2测试计划克隆问题

问题分析

你在使用Microsoft.TeamFoundationServer.Client(16.205.1版本)克隆测试计划时遇到三个核心问题:

  • 仅克隆测试计划本身,未包含测试套件
  • 调用CloneTestPlanAsync时抛出Newtonsoft.Json.JsonSerializationException,提示缺少opId字段,但克隆操作实际已执行
  • 直接调用REST API时,响应始终指向不存在的克隆操作ID 0

这些问题源于Azure DevOps Server 2020.1.2对预览版克隆API的支持有限,以及客户端SDK与服务器端API响应的兼容性差异。

解决方案

1. 绕过序列化异常,获取克隆后的测试计划

服务器返回的响应缺少SDK期望的opId字段,直接使用CloneTestPlanAsync的返回值会触发序列化异常。可以通过捕获异常后,根据计划名称查询克隆结果的方式绕过:

public async Task<TestPlan> CloneTestPlanAsync(int id, CancellationToken cancellationToken = default)
{
    var vssConnection = new VssConnection(new Uri("{PROJECT_COLLECTION_URI}"), {VssCredentials});
    TestPlanHttpClient client = await vssConnection.GetClientAsync<TestPlanHttpClient>(cancellationToken);
    TestPlan sourceTestPlan = await client.GetTestPlanByIdAsync(
        project: _projectName,
        planId: id,
        cancellationToken: cancellationToken);

    string clonedPlanName = $"{sourceTestPlan.Name} Clone";
    
    // 清理同名计划(如果存在)
    var existingPlans = await client.GetTestPlansAsync(
        project: _projectName,
        name: clonedPlanName,
        cancellationToken: cancellationToken);
    foreach (var plan in existingPlans)
    {
        await client.DeleteTestPlanAsync(_projectName, plan.Id, cancellationToken: cancellationToken);
    }

    var cloneRequestBody = new CloneTestPlanParams()
    {
        sourceTestPlan = new SourceTestPlanInfo()
        {
            id = id
        },
        destinationTestPlan = new DestinationTestPlanCloneParams()
        {
            Name = clonedPlanName,
            Iteration = sourceTestPlan.Iteration,
            Area = sourceTestPlan.Area
        },
        cloneOptions = new Microsoft.TeamFoundation.TestManagement.WebApi.CloneOptions()
        {
            CopyAllSuites = true,
            CopyAncestorHierarchy = true,
            CopyTestCases = true
        }
    };

    try
    {
        // 忽略序列化异常,克隆操作已执行
        await client.CloneTestPlanAsync(
            cloneRequestBody: cloneRequestBody,
            project: _projectName,
            cancellationToken: cancellationToken);
    }
    catch (Newtonsoft.Json.JsonSerializationException)
    {
        // 捕获异常后继续执行
    }

    // 轮询等待克隆完成
    TestPlan clonedPlan = null;
    int retryCount = 0;
    while (clonedPlan == null && retryCount < 10)
    {
        await Task.Delay(2000, cancellationToken);
        var plans = await client.GetTestPlansAsync(
            project: _projectName,
            name: clonedPlanName,
            cancellationToken: cancellationToken);
        clonedPlan = plans.FirstOrDefault();
        retryCount++;
    }

    return clonedPlan;
}

2. 手动克隆测试套件(确保套件被复制)

如果上述代码仍未克隆套件,说明Azure DevOps Server 2020.1.2的预览版API不支持CopyAllSuites参数,需要手动克隆每个套件:

在获取到克隆后的测试计划后,添加以下代码:

// 获取源计划的所有子套件
var sourceSuites = await client.GetTestSuitesForPlanAsync(
    project: _projectName,
    planId: id,
    cancellationToken: cancellationToken);

foreach (var sourceSuite in sourceSuites)
{
    if (sourceSuite.ParentSuite == null) continue; // 跳过根套件,克隆计划时已创建

    var cloneSuiteParams = new CloneTestSuiteParams()
    {
        SourceSuite = new SourceTestSuiteInfo()
        {
            Id = sourceSuite.Id,
            PlanId = id
        },
        DestinationSuite = new DestinationTestSuiteCloneParams()
        {
            Name = sourceSuite.Name,
            PlanId = clonedPlan.Id,
            ParentSuiteId = clonedPlan.RootSuite.Id
        },
        CloneOptions = new CloneOptions()
        {
            CopyTestCases = true
        }
    };

    try
    {
        await client.CloneTestSuiteAsync(
            cloneSuiteParams,
            project: _projectName,
            cancellationToken: cancellationToken);
    }
    catch (Exception ex)
    {
        Console.WriteLine($"克隆套件 {sourceSuite.Name} 失败: {ex.Message}");
    }
}

3. 适配正确的API版本

Azure DevOps Server 2020.1.2对应的REST API版本为5.1-preview.1,而非6.0-preview.2。直接调用REST API时需指定正确版本:

POST https://{instance}/{collection}/{project}/_apis/testplan/Plans/CloneOperation?api-version=5.1-preview.1

可通过返回的opId轮询克隆状态:

GET https://{instance}/{collection}/{project}/_apis/testplan/Plans/CloneOperation/{opId}?api-version=5.1-preview.1

关键说明

  • Azure DevOps Server 2020.1.2的测试计划克隆API处于早期预览阶段,部分参数功能未完全生效
  • 手动克隆套件是当前版本下确保套件被复制的可靠方式
  • 克隆操作是异步执行的,必须轮询等待完成后再获取结果

内容的提问来源于stack exchange,提问作者Huadara

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 20:04:55