如何使用 .NET SDK 客户端获取测试用例的共享步骤详细信息?

How can I get the shared steps details for a test case using the .NET SDK client?

我使用 .NET SDK 客户端(NuGet 上提供的 16.156.0 预览版),但我搜索了如何获取包含共享步骤的测试用例步骤。 字段parameterizedString好像包含了所有的测试步骤,但是当包含共享步骤的时候,XML内容不清楚

我用来获取测试用例的所有测试步骤的代码示例:

private void ReadTestCaseSteps(Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.TestCase testCase)
{
    foreach (var field in testCase.workItem.WorkItemFields.OfType<JObject>())
    {
        var stepsContent = ((JValue)((JContainer)field.First).First).Value.ToString();

        using (TextReader stepsReader = new StringReader(stepsContent))
        {
            var serializer = new XmlSerializer(typeof(steps));
            var steps = (steps)serializer.Deserialize(stepsReader);
        }
    }
}

class "steps" 是此样本的 XML 描述:

// NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0.
/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class steps
{

    private stepsStep stepField;

    private stepsCompref comprefField;

    private byte idField;

    private byte lastField;

    /// <remarks/>
    public stepsStep step
    {
        get
        {
            return this.stepField;
        }
        set
        {
            this.stepField = value;
        }
    }

    /// <remarks/>
    public stepsCompref compref
    {
        get
        {
            return this.comprefField;
        }
        set
        {
            this.comprefField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public byte id
    {
        get
        {
            return this.idField;
        }
        set
        {
            this.idField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public byte last
    {
        get
        {
            return this.lastField;
        }
        set
        {
            this.lastField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class stepsStep
{

    private stepsStepParameterizedString[] parameterizedStringField;

    private object descriptionField;

    private byte idField;

    private string typeField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("parameterizedString")]
    public stepsStepParameterizedString[] parameterizedString
    {
        get
        {
            return this.parameterizedStringField;
        }
        set
        {
            this.parameterizedStringField = value;
        }
    }

    /// <remarks/>
    public object description
    {
        get
        {
            return this.descriptionField;
        }
        set
        {
            this.descriptionField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public byte id
    {
        get
        {
            return this.idField;
        }
        set
        {
            this.idField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string type
    {
        get
        {
            return this.typeField;
        }
        set
        {
            this.typeField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class stepsStepParameterizedString
{

    private bool isformattedField;

    private string valueField;

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public bool isformatted
    {
        get
        {
            return this.isformattedField;
        }
        set
        {
            this.isformattedField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlTextAttribute()]
    public string Value
    {
        get
        {
            return this.valueField;
        }
        set
        {
            this.valueField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class stepsCompref
{

    private stepsComprefStep[] stepField;

    private stepsComprefCompref comprefField;

    private byte idField;

    private ushort refField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("step")]
    public stepsComprefStep[] step
    {
        get
        {
            return this.stepField;
        }
        set
        {
            this.stepField = value;
        }
    }

    /// <remarks/>
    public stepsComprefCompref compref
    {
        get
        {
            return this.comprefField;
        }
        set
        {
            this.comprefField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public byte id
    {
        get
        {
            return this.idField;
        }
        set
        {
            this.idField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public ushort @ref
    {
        get
        {
            return this.refField;
        }
        set
        {
            this.refField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class stepsComprefStep
{

    private stepsComprefStepParameterizedString[] parameterizedStringField;

    private object descriptionField;

    private byte idField;

    private string typeField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("parameterizedString")]
    public stepsComprefStepParameterizedString[] parameterizedString
    {
        get
        {
            return this.parameterizedStringField;
        }
        set
        {
            this.parameterizedStringField = value;
        }
    }

    /// <remarks/>
    public object description
    {
        get
        {
            return this.descriptionField;
        }
        set
        {
            this.descriptionField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public byte id
    {
        get
        {
            return this.idField;
        }
        set
        {
            this.idField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string type
    {
        get
        {
            return this.typeField;
        }
        set
        {
            this.typeField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class stepsComprefStepParameterizedString
{

    private bool isformattedField;

    private string valueField;

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public bool isformatted
    {
        get
        {
            return this.isformattedField;
        }
        set
        {
            this.isformattedField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlTextAttribute()]
    public string Value
    {
        get
        {
            return this.valueField;
        }
        set
        {
            this.valueField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class stepsComprefCompref
{

    private stepsComprefComprefStep[] stepField;

    private byte idField;

    private ushort refField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("step")]
    public stepsComprefComprefStep[] step
    {
        get
        {
            return this.stepField;
        }
        set
        {
            this.stepField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public byte id
    {
        get
        {
            return this.idField;
        }
        set
        {
            this.idField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public ushort @ref
    {
        get
        {
            return this.refField;
        }
        set
        {
            this.refField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class stepsComprefComprefStep
{

    private stepsComprefComprefStepParameterizedString[] parameterizedStringField;

    private object descriptionField;

    private byte idField;

    private string typeField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("parameterizedString")]
    public stepsComprefComprefStepParameterizedString[] parameterizedString
    {
        get
        {
            return this.parameterizedStringField;
        }
        set
        {
            this.parameterizedStringField = value;
        }
    }

    /// <remarks/>
    public object description
    {
        get
        {
            return this.descriptionField;
        }
        set
        {
            this.descriptionField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public byte id
    {
        get
        {
            return this.idField;
        }
        set
        {
            this.idField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string type
    {
        get
        {
            return this.typeField;
        }
        set
        {
            this.typeField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class stepsComprefComprefStepParameterizedString
{

    private bool isformattedField;

    private string valueField;

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public bool isformatted
    {
        get
        {
            return this.isformattedField;
        }
        set
        {
            this.isformattedField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlTextAttribute()]
    public string Value
    {
        get
        {
            return this.valueField;
        }
        set
        {
            this.valueField = value;
        }
    }
}

用共享步骤描述步骤的XML可以这样:

<steps id="0" last="14">
    <step id="2" type="ValidateStep">
        <parameterizedString isformatted="true">&lt;DIV&gt;&lt;DIV&gt;&lt;P&gt;Step 1&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;</parameterizedString>
        <parameterizedString isformatted="true">&lt;DIV&gt;&lt;P&gt;Result 1&lt;/P&gt;&lt;/DIV&gt;</parameterizedString>
        <description/>
    </step>
    <compref id="6" ref="8712">
        <step id="5" type="ActionStep">
            <parameterizedString isformatted="true">&lt;DIV&gt;&lt;P&gt;Step 4&lt;/P&gt;&lt;/DIV&gt;</parameterizedString>
            <parameterizedString isformatted="true">&lt;DIV&gt;&lt;P&gt;&lt;BR/&gt;&lt;/P&gt;&lt;/DIV&gt;</parameterizedString>
            <description/>
        </step>
        <step id="7" type="ActionStep">
            <parameterizedString isformatted="true">&lt;DIV&gt;&lt;P&gt;Step 5&lt;/P&gt;&lt;/DIV&gt;</parameterizedString>
            <parameterizedString isformatted="true">&lt;DIV&gt;&lt;P&gt;&lt;BR/&gt;&lt;/P&gt;&lt;/DIV&gt;</parameterizedString>
            <description/>
        </step>
        <compref id="14" ref="8713">
            <step id="10" type="ActionStep">
                <parameterizedString isformatted="true">&lt;DIV&gt;&lt;DIV&gt;&lt;P&gt;Step 8&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;</parameterizedString>
                <parameterizedString isformatted="true">&lt;DIV&gt;&lt;P&gt;&lt;BR/&gt;&lt;/P&gt;&lt;/DIV&gt;</parameterizedString>
                <description/>
            </step>
            <step id="11" type="ActionStep">
                <parameterizedString isformatted="true">&lt;DIV&gt;&lt;DIV&gt;&lt;P&gt;Step 9&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;</parameterizedString>
                <parameterizedString isformatted="true">&lt;DIV&gt;&lt;P&gt;&lt;BR/&gt;&lt;/P&gt;&lt;/DIV&gt;</parameterizedString>
                <description/>
            </step>
            <step id="12" type="ActionStep">
                <parameterizedString isformatted="true">&lt;DIV&gt;&lt;DIV&gt;&lt;P&gt;Step 10&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;</parameterizedString>
                <parameterizedString isformatted="true">&lt;DIV&gt;&lt;P&gt;&lt;BR/&gt;&lt;/P&gt;&lt;/DIV&gt;</parameterizedString>
                <description/>
            </step>
            <step id="13" type="ActionStep">
                <parameterizedString isformatted="true">&lt;DIV&gt;&lt;DIV&gt;&lt;P&gt;&lt;BR/&gt;&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;</parameterizedString>
                <parameterizedString isformatted="true">&lt;DIV&gt;&lt;P&gt;&lt;BR/&gt;&lt;/P&gt;&lt;/DIV&gt;</parameterizedString>
                <description/>
            </step>
        </compref>
    </compref>
</steps>

所以我不明白如何使用 API 的共享步骤来阅读和管理测试用例步骤,以便将此内容转换为详细步骤列表(描述、预期结果).

你能告诉我吗?

我测试发现分享步骤是由comprefref属性引用的。 ref属性的值实际上是共享步骤的id

元素 compref 中未显示详细的分享步骤,它只有分享步骤的 ref id。 元素 compref 下的元素 step 不是共享步骤。

获得ref的值后,即共享步骤的id。您可以再次调用 API 以获取共享步骤中的详细步骤。

GetWorkItemAsync(Int32, IEnumerable<String>, Nullable<DateTime>, Nullable<WorkItemExpand>, Object, CancellationToken)

正如您所说,compref xml 内容不清楚。您可能需要重新定义步骤 class 以反序列化 xml 内容,并使用 ref 值再次调用 api。

你说得对,我需要将共享步骤作为工作项阅读,并阅读字段 "Microsoft.VSTS.TCM.Steps" 中的步骤。

我还更改了 xml class "steps" 以管理子步骤:

// NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0.
/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class steps
{
    private stepsStep[] stepField;

    private steps comprefField;

    private int idField;

    private int lastField;

    private int refField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("step")]
    public stepsStep[] step
    {
        get
        {
            return this.stepField;
        }
        set
        {
            this.stepField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("compref")]
    public steps compref
    {
        get
        {
            return this.comprefField;
        }
        set
        {
            this.comprefField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public int id
    {
        get
        {
            return this.idField;
        }
        set
        {
            this.idField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public int last
    {
        get
        {
            return this.lastField;
        }
        set
        {
            this.lastField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public int @ref
    {
        get
        {
            return this.refField;
        }
        set
        {
            this.refField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class stepsStep
{

    private stepsStepParameterizedString[] parameterizedStringField;

    private object descriptionField;

    private byte idField;

    private string typeField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("parameterizedString")]
    public stepsStepParameterizedString[] parameterizedString
    {
        get
        {
            return this.parameterizedStringField;
        }
        set
        {
            this.parameterizedStringField = value;
        }
    }

    /// <remarks/>
    public object description
    {
        get
        {
            return this.descriptionField;
        }
        set
        {
            this.descriptionField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public byte id
    {
        get
        {
            return this.idField;
        }
        set
        {
            this.idField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string type
    {
        get
        {
            return this.typeField;
        }
        set
        {
            this.typeField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class stepsStepParameterizedString
{

    private bool isformattedField;

    private string valueField;

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public bool isformatted
    {
        get
        {
            return this.isformattedField;
        }
        set
        {
            this.isformattedField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlTextAttribute()]
    public string Value
    {
        get
        {
            return this.valueField;
        }
        set
        {
            this.valueField = value;
        }
    }
}

xml 内容不是很可读;) 感谢您的帮助。