C# 通过REST API向TFS 2018测试用例发布测试结果

C# 通过REST API向TFS 2018测试用例发布测试结果,c#,.net,rest,tfs,automated-tests,C#,.net,Rest,Tfs,Automated Tests,目前我们正在使用mstest.exe运行自动测试,然后它将创建一个.trx结果文件。然后,我们使用tcm.exe将这些结果发布到TFS服务器上的一些测试套件/测试用例中 我们希望不再使用tcm,而是使用TFS REST API从.trx结果文件发布结果 我已经读过一些关于这方面的文章,但是没有什么是特定于使用TFS扩展客户机类的(例如TestManagementHttpClient),它只列举了要使用的实际URL。它也没有给出很多关于它期望的参数的例子 Microsoft.TeamFoundat

目前我们正在使用mstest.exe运行自动测试,然后它将创建一个.trx结果文件。然后,我们使用tcm.exe将这些结果发布到TFS服务器上的一些测试套件/测试用例中

我们希望不再使用tcm,而是使用TFS REST API从.trx结果文件发布结果

我已经读过一些关于这方面的文章,但是没有什么是特定于使用TFS扩展客户机类的(例如
TestManagementHttpClient
),它只列举了要使用的实际URL。它也没有给出很多关于它期望的参数的例子

Microsoft.TeamFoundation.TestManagement.WebApi名称空间有一个官方名称空间,这有点帮助,但同样没有任何示例/示例来了解每个函数需要哪些参数

由于我对testpoints/testruns的概念不太熟悉,无法操纵表示它们的类,因此,这个问题还不够详细,我无法理解如何在我的情况下应用它

我猜一个测试运行有多个测试点(每个测试用例运行一个测试点?)?在这种情况下,我应该假设我需要为每个测试结果创建一个测试点。如果是,我怎么知道该给哪个ID?上面的示例硬编码“3”作为其值

如果有人能解释上面的示例,并提供一个与我的用例相关的更好/更完整的示例(从.trx文件开始,并将这些结果发布到与某个测试套件下的链接自动化项相匹配的测试用例),帮助我理解所有内容是如何相互关联的,我将不胜感激


谢谢。

因此,根据我在问题中链接的示例/示例回答我自己的问题:

  • 您需要使用
    TestManagementHttpClient.GetTestConfigurationsAsync()

  • 然后,您需要使用
    TestManagementHttpClient.GetPointsAsync()获取该测试用例/测试配置组合的所有测试点

  • 然后需要创建一个测试运行。这是通过声明一个新的
    RunCreateModel
    对象来完成的,方法是至少指定您以前获取的测试点ID。您可能还需要填写大量的参数(
    buildId
    isAutomated
    ,等等)。然后需要调用
    TestManagementHttpClient.CreateTestRunAsync()
    来实际创建它

  • 步骤3实际上在测试运行下为创建时指定的每个测试点创建了空测试结果。您需要使用
    TestManagementHttpClient.GetTestResultsAsync()
    获取它们,并使用
    TestCaseResult.TestCase.Id
    属性修改它们上的
    Output
    属性,以了解哪个测试用例的结果。您可能还需要填写其他属性,例如
    状态
    ,等等。同样,您需要使用
    TestManagementHttpClient.UpdateTestResultsAsync()将这些修改推送到TFS

  • 最后一步是通过使用
    state=“completed”
    创建一个
    RunUpdateModel
    对象,然后调用
    TestManagementHttpClient.updatestrunasync()

  • 下面是我最后编写的函数,它可以实现所有这些功能,用F#编写:

    //测试点是测试用例与测试配置的配对
    让createTestRun(httpClient:TestManagementHttpClient)(testRunName:string)(teamProjectName:string)(testPlanId:int)(testSuiteId:int)(testCaseIdsAndResults:seq)(buildId:int)(cancellationToken:cancellationToken)=异步{
    设testPlanIdString=testPlanId.ToString()
    let plan=new ShallowReference(testPlanIdString)
    让!testConfigurations=httpClient.GetTestConfigurationsAsync(teamProjectName,cancellationToken=cancellationToken)|>Async.WaitTask
    让defaultTestConfiguration=testConfigurations |>Seq.find(fun c->c.IsDefault)//TODO:我们现在只使用默认配置。我们总是想要这样吗?
    让rec getTestPoints(testdsandresults:(int*string)列表)(testPoints:TestPoint[])=async{
    将测试和结果与
    |(testId:):rest->
    let!fetchedTestPoints=httpClient.GetPointsAsync(teamProjectName,testPlanId,testSuiteId,testCaseId=testId.ToString(),cancellationToken=cancellationToken)|>Async.WaitTask
    让testPoint=fetchedTestPoints |>Seq.find(fun p->p.Configuration.Id=defaultTestConfiguration.Id.ToString())
    让newTestPointsList=Array.append测试点[|测试点|]
    return!getTestPoints rest newTestPoints列表
    | _ ->
    返回测试点
    }
    let!testPoints=getTestPoints(List.ofSeq testCaseIdsAndResults)Array.empty
    让testPointIds=testPoints |>Array.map(fun p->p.Id)
    让runCreateModel=new runCreateModel(name=testRunName,plan=plan,buildId=buildId,isAutomated=new Nullable(true),pointid=testpointid)
    让!testRun=httpClient.CreateTestRunAsync(runCreateModel,teamProjectName,cancellationToken=cancellationToken)|>Async.WaitTask
    let!emptyResults=httpClient.GetTestResultsSync(project=teamProjectName,runId=testRun.Id,Outlets=new List(),cancellationToken=cancellationToken)|>Async.Task
    let rec createCaseResults(testisAndResults:(int*string)列表)(结果:TestCaseResult[])=async{
    将测试和结果与
    |(testId,testResult)::rest->
    让casesult=emptyResults |>Seq.find(fun r->r.TestCase.Id=testId.ToString())
    caseResult.State Async.Task
    让runmodel=newrunupdatemodel(state=“Completed”);
    let!u=httpClient.UpdateTestRunAsync(runmodel,teamProjectName,testRun.Id,cancellationTo
    
    // A test point is a pairing of a test case with a test configuration
    let createTestRun (httpClient:TestManagementHttpClient) (testRunName:string) (teamProjectName:string) (testPlanId:int) (testSuiteId:int) (testCaseIdsAndResults:seq<(int * string)>) (buildId:int) (cancellationToken:CancellationToken) = async {
        let testPlanIdString = testPlanId.ToString()
        let plan = new ShallowReference(testPlanIdString)
    
        let! testConfigurations = httpClient.GetTestConfigurationsAsync(teamProjectName, cancellationToken = cancellationToken) |> Async.AwaitTask
        let defaultTestConfiguration = testConfigurations |> Seq.find (fun c -> c.IsDefault) // TODO: We only use the default configuration for now. Do we always want this?
    
        let rec getTestPoints (testIdsAndResults:(int * string) list) (testPoints:TestPoint[]) = async {
            match testIdsAndResults with
            | (testId, _)::rest ->
                let! fetchedTestPoints = httpClient.GetPointsAsync(teamProjectName, testPlanId, testSuiteId, testCaseId = testId.ToString(), cancellationToken = cancellationToken) |> Async.AwaitTask
                let testPoint = fetchedTestPoints |> Seq.find (fun p -> p.Configuration.Id = defaultTestConfiguration.Id.ToString())
                let newTestPointsList = Array.append testPoints [|testPoint|]
                return! getTestPoints rest newTestPointsList
            | _ ->
                return testPoints
        }
        let! testPoints = getTestPoints (List.ofSeq testCaseIdsAndResults) Array.empty
        let testPointIds = testPoints |> Array.map (fun p -> p.Id)
    
        let runCreateModel = new RunCreateModel(name = testRunName, plan = plan, buildId = buildId, isAutomated = new Nullable<bool>(true), pointIds = testPointIds)
        let! testRun = httpClient.CreateTestRunAsync(runCreateModel, teamProjectName, cancellationToken = cancellationToken) |> Async.AwaitTask
        let! emptyResults = httpClient.GetTestResultsAsync(project = teamProjectName, runId = testRun.Id, outcomes = new List<TestOutcome>(), cancellationToken = cancellationToken) |> Async.AwaitTask
    
        let rec createCaseResults (testIdsAndResults:(int * string) list) (results:TestCaseResult[]) = async {
            match testIdsAndResults with
            | (testId, testResult)::rest ->
                let caseResult = emptyResults |> Seq.find (fun r -> r.TestCase.Id = testId.ToString())
                caseResult.State <- "Completed"
                caseResult.Outcome <- testResult // "passed", "failed", "never run", "not applicable"
                let newResultsList = Array.append results [|caseResult|]
                return! createCaseResults rest newResultsList
            | _ ->
                return results
        }
        let! results = createCaseResults (List.ofSeq testCaseIdsAndResults) Array.empty
        let! _ = httpClient.UpdateTestResultsAsync(results, teamProjectName, testRun.Id, cancellationToken = cancellationToken) |> Async.AwaitTask
    
        let runmodel = new RunUpdateModel(state = "Completed");
        let! _ = httpClient.UpdateTestRunAsync(runmodel, teamProjectName, testRun.Id, cancellationToken = cancellationToken) |> Async.AwaitTask
    
        ()
    }