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



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

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

我已经阅读了一些关于REST API的相关文档,但没有任何特定于使用TFS扩展客户端类(如TestManagementHttpClient)的内容,它只列举了要使用的实际URL。它也没有给出很多关于它期望的参数的例子。

Microsoft.TeamFoundation.TestManagement.WebApi命名空间的官方.NET参考文档对此有所帮助,但它也没有任何示例/示例来了解每个函数所需的参数。

我能找到的唯一例子/样本不够详细,我无法理解如何在我的情况下应用它,因为我对测试点/测试运行的概念不够熟悉,无法操作代表它们的类。

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

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

谢谢。

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

  1. 您需要使用TestManagementHttpClient.GetTestConfigurationsAsync()获得您想要的测试配置

  2. 然后,您将希望使用TestManagementHttpClient.GetPointsAsync()获取该测试用例/测试配置组合的所有测试点

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

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

  5. 最后一步是通过使用state = "Completed"创建一个RunUpdateModel对象,然后调用TestManagementHttpClient.UpdateTestRunAsync(),将测试运行设置为已完成

这是我最终编写的函数,它完成了所有这些,用F#编写:

// 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
()
}

最新更新