Xunit 测试结果附件不显示

问题描述 投票:0回答:1

我们使用 C# selenium 和 Xunit(2.7.0) 进行自动化。我们有一个 Visual Studio 测试任务,可以通过测试选择触发“测试运行”。目前我们正在按照这个附件-创建测试结果附件来上传测试日志文件。我们没有遇到任何有关上传者逻辑的问题,但我们看不到任何附件。这是我们的逻辑 - 这就是我们如何称呼上传者

 try
 {
     // Run asynchronous upload operations asynchronously
     Task.Run(async () =>
     {
         try
         {
             // Upload log file
             string pat = Environment.GetEnvironmentVariable("AZURE_DEVOPS_PAT");
             string runId = devOpsUploader.GetLatestRunId(pat);
             var testResults = await devOpsUploader.FetchTestResults(runId);
             string testCaseResultId = testResults.FirstOrDefault()?.Id.ToString() ?? "";
             string comment = "Log file attachment";
             string basePath = @"D:\a\1\s\TestProject1\bin\Debug\netcoreapp3.1\Logs";
             string fileName = $"CreateTnMProjectTest_{DateTime.Now:yyyyMMdd_HHmmss}.txt";
             string fullPath = Path.Combine(basePath, fileName);
          
             await devOpsUploader.UploadLogFile(runId, testCaseResultId, fullPath, comment);
         }
         catch (Exception ex)
         {
             Console.WriteLine($"Error occurred while uploading log file: {ex.Message}");
         }
     }).Wait();
 }
 catch (Exception ex)
 {
     Console.WriteLine($"Error occurred while running asynchronous operations: {ex.Message}");
 }

这是我们的上传方法

public async Task UploadLogFile(string runId, string testCaseResultId, string logFilePath, string comment)
{
    byte[] fileBytes = File.ReadAllBytes(logFilePath);
    string fileContentBase64 = Convert.ToBase64String(fileBytes);
    var streamContent = new ByteArrayContent(fileBytes);
    streamContent.Headers.ContentType = MediaTypeHeaderValue.Parse("text/plain");

    var attachment = new
    {
        stream = fileContentBase64,
        fileName = Path.GetFileName(logFilePath),
        comment,
        attachmentType = "GeneralAttachment"
    };
    string attachmentJson = JsonConvert.SerializeObject(attachment);
    var content = new StringContent(attachmentJson, Encoding.UTF8, "application/json");
    string apiUrl = $"_apis/test/Runs/{runId}/Results/{testCaseResultId}/attachments?api-version=6.0-preview.1";
    string fullUrl = client.BaseAddress + apiUrl;

    var response = await client.PostAsync(fullUrl, content);

    if (!response.IsSuccessStatusCode)
    {
        var responseContent = await response.Content.ReadAsStringAsync();
        var responseHeaders = response.Headers.ToString();
        Console.WriteLine($"Response Headers: {responseHeaders}");
        Console.WriteLine($"Response Content: {responseContent}");
        string errorMessage = await response.Content.ReadAsStringAsync();
        throw new Exception($"Failed to upload log file: {errorMessage}");
    }
    else
    {
        Console.WriteLine("File uploaded successfully.");
        Console.WriteLine($"Status Code: {(int)response.StatusCode} {response.ReasonPhrase}");
    }
}
public string GetLatestRunId(string pat)
{
    string organization = "*******";
    string project = "Training";

    // Construct the URL for fetching test runs
    string apiUrl = $"https://dev.azure.com/{organization}/{project}/_apis/test/runs";

    // Initialize HttpClient
    using (HttpClient httpClient = new HttpClient())
    {
        // Set up HttpClient headers (authentication may be required)
        httpClient.DefaultRequestHeaders.Accept.Clear();
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($":{pat}")));
        httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/octet-stream");


        // Perform HTTP GET request to fetch test runs
        HttpResponseMessage response = httpClient.GetAsync(apiUrl).Result;

        // Check if the response is successful
        response.EnsureSuccessStatusCode();

        var testRunData = response.Content.ReadAsStringAsync().Result;
        // Deserialize the response content into a collection of Run objects
        var runs = JsonConvert.DeserializeObject<TestRunCollection>(testRunData);
        // Ensure there are runs available
        if (runs != null && runs.Count > 0)
        {
            // Sort the runs by StartTime in descending order to get the latest run first
            var latestRun = runs.OrderByDescending(r => r.StartTime).First();

            // Return the ID of the latest run
            return latestRun.Id.ToString();
        }
        else
        {
            throw new InvalidOperationException("No test runs found.");
        }
    }
}
public async Task<List<TestResult>> FetchTestResults(string runId)
{
    string organization = "********";
    string project = "Training";
    string apiUrl = $"https://dev.azure.com/{organization}/{project}/_apis/test/Runs/{runId}/Results?api-version=6.0-preview.1";

    using (HttpClient httpClient = new HttpClient())
    {
        string pat = Environment.GetEnvironmentVariable("AZURE_DEVOPS_PAT");
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($":{pat}")));

        HttpResponseMessage response = await httpClient.GetAsync(apiUrl);
        response.EnsureSuccessStatusCode();

        var testResultData = await response.Content.ReadAsStringAsync();
        var testResults = JsonConvert.DeserializeObject<List<dynamic>>(testResultData);

        List<TestResult> resultList = new List<TestResult>();

        foreach (var result in testResults)
        {
            // Create a new TestCase object
            var testCase = new TestCase { Name = result.testCase.name };

            // Create a new TestResult object and add it to the list
            resultList.Add(new TestResult(testCase)
            {
                Id = result.id,
                Outcome = result.outcome,
                RunId = runId
            }) ;
        }

        return resultList.Select(result => new TestResult(
       new TestCase { Name = result.TestCase.Name }
   )
        {
            Id = result.Id,
            Outcome = result.Outcome,
            RunId = runId // Add this line 
        }).ToList();
    };
    }

尝试了上述方法,但是我们没有看到任何文件被上传。文件正在生成,但未上传到附件。enter image description here`

xunit azure-devops-rest-api
1个回答
0
投票

在本地 PowerShell 中使用此 API 进行测试期间,它可以通过管道为

VSTest
的测试结果创建附件文件。看来您还没有找到正确的测试结果或测试运行。

为此,建议使用此API通过BuildId获取测试结果(包括测试运行id),并使用另一个API添加测试结果附件。在下面的示例中,我在

VSTest
步骤之后在PowerShell脚本中调用了API请求,因为在
VSTest
步骤完成并发布测试结果之前我们无法找到测试运行。

pool:
  vmImage: windows-latest

variables:
  orgName: ${{ split(variables['System.CollectionUri'], '/')[3] }} # Split orgName from URL like https://dev.azure.com/OrgName/

steps:
- task: DotNetCoreCLI@2
  inputs:
    command: 'restore'
    projects: '**/*.sln'
    feedsToUse: 'select'
  displayName: DotNet Restore
- task: VSBuild@1
  inputs:
    solution: '**\*.sln'
  displayName: VS Build
- task: VSTest@3
  inputs:
    testSelector: 'testAssemblies'
    testAssemblyVer2: |
      **\*test*.dll
      !**\*TestAdapter.dll
      !**\obj\**
    searchFolder: '$(System.DefaultWorkingDirectory)'
  displayName: VS Test
  continueOnError: true
- powershell: |
    Write-Host "orgName is $(orgName)"

    # Generate attachment file for test
    New-Item -Path "TestAttachmentFile-$(Build.BuildId).txt" -ItemType File -Value "TestAttachmentFile-$(Build.BuildId)"
    cat TestAttachmentFile-$(Build.BuildId).txt

    # Call Rest APIs authenticating against System.AccessToken 
    $headers = @{
        'Authorization' = 'Bearer ' + "$(System.AccessToken)"
        'Content-Type' = 'application/json'
    }
    
    Write-Host "================1. Get test results by Build.BuildId:================"
    # Resultsbybuild - List GET https://vstmr.dev.azure.com/{organization}/{project}/_apis/testresults/resultsbybuild?buildId={buildId}&api-version=7.1-preview.1
    $testResultsByBuildURL= "https://vstmr.dev.azure.com/$(orgName)/$(System.TeamProject)/_apis/testresults/resultsbybuild?buildId=$(Build.BuildId)&api-version=7.1-preview.1"
    $testResultsByBuild = Invoke-RestMethod -Method Get -Uri $testResultsByBuildURL -Headers $headers
    
    # Filter test results by test case title and extract test result ID
    $testCaseTitle = "SucceededTest"
    $targetTestResult = $testResultsByBuild.value | Where-Object { $_.testCaseTitle -eq $testCaseTitle }
    if ($targetTestResult) {
        $testResultId = $targetTestResult.id
        $testRunId = $targetTestResult.runId
        Write-Host "Test Result ID for '$testCaseTitle' of Test Run(id:$testRunId): $testResultId"
    } else {
        Write-Host "Test Result '$testResultName' not found."
    }

    Write-Host "================2. Create attachment for test result:================"
    # Attachments - Create Test Result Attachment POST https://vstmr.dev.azure.com/{organization}/{project}/_apis/testresults/runs/{runId}/results/{testCaseResultId}/attachments?api-version=7.1-preview.1
    $addAttachmentURL = "https://vstmr.dev.azure.com/$(orgName)/$(System.TeamProject)/_apis/testresults/runs/$testRunId/results/$testResultId/attachments?api-version=7.1-preview.1"
    
    $FilePath = "$(System.DefaultWorkingDirectory)\TestAttachmentFile-$(Build.BuildId).txt"
    $FileContent = Get-Content $FilePath -Raw
    $fileContentInBytes = [System.Text.Encoding]::UTF8.GetBytes($FileContent)
    $fileContentEncoded = [System.Convert]::ToBase64String($fileContentInBytes)

    $body = @{
        'stream' = $fileContentEncoded
        'fileName' = 'TestAttachmentFile-$(Build.BuildId).txt'
        'comment' = 'Create attachment for test result from $(Build.BuildId)'
        'attachmentType' = 'GeneralAttachment'
    } | ConvertTo-Json

    Invoke-RestMethod -Method Post -Uri $addAttachmentURL -Headers $headers -Body $body
  displayName: Use APIs to locate and create attachment to test result

© www.soinside.com 2019 - 2024. All rights reserved.