如何使用问题匹配器将 xUnit/dotnet 测试输出转换为 GitHub 操作中的注释?

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

我有一个使用

dotnet test
运行 .NET xUnit 测试的 GitHub 操作:

jobs:
  build-net:
    name: .NET build & test
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Setup .NET
      uses: actions/setup-dotnet@v3
      with:
        dotnet-version: 7.0.100      
    - name: Restore dependencies
      run: dotnet restore
    - name: Build
      run: dotnet build --no-restore
    - name: Test
      run: dotnet test --no-build

测试步骤为每个测试输出类似这样的内容:

  Failed Library.Tests.UnitTest1.DeliberateFail2 [< 1 ms]
  Error Message:
   System.Exception : Error message
  Stack Trace:
     at Library.Tests.UnitTest1.DeliberateFail2() in /home/runner/work/Library/Library.Tests/UnitTest1.cs:line 30
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)

然后是总结:

Failed!  - Failed:     2, Passed:   133, Skipped:     0, Total:   135, Duration: 639 ms - Library.Tests.dll (net7.0)
Error: Process completed with exit code 1.

这会导致操作中出现单步失败消息:

正如您所看到的,来自

dotnet build
的空引用警告指向一行代码(并将出现在 PR 中该行的旁边),而
dotnet test
只给我
Process completed with exit code 1

我不只是想要一个失败的构建步骤,我想要每个失败的测试都有一个注释

现有方法可以解决此问题:

但它们都涉及对我的操作管道的更改或新的依赖项,我都不想要

根据 GitHub 的文档,我应该能够使用问题匹配器来修复此问题,这是一个将

dotnet test
输出转换为注释格式的正则表达式(类似于 VSCode 中的相同模式)。

解析

dotnet test
输出的正则表达式看起来像
^\s*Failed\s(.*)([\s\S]*?)(Stack\sTrace:\s*at\s)(.*)\s+in\s+(.*):line\s+(\d+)\s*$
,我将其添加为
.github/xunit.json
:

{
  "problemMatcher": [
    {
      "owner": "xunit",
      "pattern": [ 
        {
          "regexp": "^\\s*Failed\\s(.*)([\\s\\S]*?)(Stack\\sTrace:\\s*at\\s)(.*)\\s+in\\s+(.*):line\\s+(\\d+)\\s*$",
          "file": 5,
          "fromPath": 5,
          "line": 6,
          "message": 2
        }
      ]
    }
  ]
}

然后我使用

add-matcher
来包含此内容:

    - name: Build
      run: dotnet build --no-restore
    - name: set matcher
      run: echo "::add-matcher::${{ github.workspace }}/.github/xunit.json"
    - name: Test
      run: dotnet test --no-build --logger "trx;LogFileName=test-results.trx"

这不起作用 - 我仍然没有得到注释。

我也尝试过多行问题匹配:

{
  "problemMatcher": [
    {
      "owner": "xunit",
      "pattern": [ 
        {
          "regexp": "^\\s*Failed\\s(.*)$",
          "message": 1
        },
        {
          "regexp": "^\\s*at\\s(.*)\\s+in\\s+(.*):line\\s+(\\d+)\\s*$",
          "file": 2,
          "fromPath": 2,
          "line": 3,
        }
      ]
    }
  ]
}

有人已经为

dotnet test
输出构建了 GitHub 问题匹配器吗?看起来很疯狂,没有其他人这样做过吗?

任何人都可以帮助修复这些正则表达式(或指出我在配置操作时做错了什么)?

.net yaml github-actions mstest xunit
2个回答
3
投票

测试了您的场景,它确实生成了注释。

这是一个测试工作流程及其输出:

name: problem_matcher_test

on: workflow_dispatch

jobs:
  ci:
    runs-on: ubuntu-latest

    steps:
    - name: Add problem matcher
      env:
        PROBLEM_MATCHER_CONFIG: |
          {
            "problemMatcher": [
              {
                "owner": "xunit",
                "pattern": [
                  {
                    "regexp": "^\\s*Failed\\s(.*)$",
                    "message": 1
                  },
                  {
                    "regexp": "^\\s*at\\s(.*)\\s+in\\s+(.*):line\\s+(\\d+)\\s*$",
                    "file": 2,
                    "fromPath": 2,
                    "line": 3
                  }
                ]
              }
            ]
          }
      run: |
        echo "$PROBLEM_MATCHER_CONFIG" > xunit.json
        echo "$PWD/xunit.json"
        cat -n "$PWD/xunit.json"
        echo "::add-matcher::$PWD/xunit.json"

    - name: Dumping Logs
      env:
        LOGS: |
          Failed Library.Tests.UnitTest1.DeliberateFail1 [< 1 ms]
            at Library.Tests.UnitTest1.DeliberateFail1() in /home/runner/work/Library/Library.Tests/UnitTests.cs:line 1
          Failed Library.Tests.UnitTest1.DeliberateFail2 [< 1 ms]
            at Library.Tests.UnitTest1.DeliberateFail2() in /home/runner/work/Library/Library.Tests/UnitTests.cs:line 2
      run: |
        echo "$LOGS"

    - name: Remove problem matcher
      run: |
        echo "::remove-matcher::$PWD/xunit.json"

输出:

有了有效的文件路径,它应该生成完整的注释。在此处观察有关路径的这些调试日志:

但是,例外情况是多行,并且可能并不总是包含相同数量的行。对于上述测试,我仅将日志剥离到所需的行。


显然,由于其限制以及缺乏配置选项,问题匹配器解决方案无法针对多个多行错误进行扩展。

IMO,如果您不想使用现有的解决方案,将测试日志转储到文件然后扫描这些日志以获取所需的输出更有意义。


0
投票

我一直在尝试解决多行匹配的限制,所以这是我的问题匹配器:

PROBLEM_MATCHER_CONFIG: |
  {
    "problemMatcher": [
      {
        "owner": "xunit",
        "pattern": [
          {
            "regexp": "^\\s*Failed\\s(.*)$"
          },
          {
            "regexp": "^\\s*Error Message:\\s*$"
          },
          {
            "regexp": "^\\s*(.*?)\\s*$",
            "message": 1
          },
          {
            "regexp": "^\\s*Expected:"
          },
          {
            "regexp": "^\\s*Actual:"
          },
          {
            "regexp": "^\\s*Stack Trace:\\s*$"
          },
          {
            "regexp": "^\\s*at\\s(.*)\\s+in\\s+(.*):line\\s+(\\d+)\\s*$",
            "file": 2,
            "fromPath": 2,
            "line": 3
          }
        ]
      },
      {
        "owner": "xunit.exc",
        "pattern": [
          {
            "regexp": "^\\s*Failed\\s(.*)$"
          },
          {
            "regexp": "^\\s*Error Message:\\s*$"
          },
          {
            "regexp": "^\\s*(.*Exception.*)\\s*$",
            "message": 1
          },
          {
            "regexp": "^\\s*Stack Trace:\\s*$"
          },
          {
            "regexp": "^\\s*at\\s(.*)\\s+in\\s+(.*):line\\s+(\\d+)\\s*$",
            "file": 2,
            "fromPath": 2,
            "line": 3
          }
        ]
      }
    ]
  }

必须定义 2 个所有者才能匹配不同的输出格式。第一个与常规 dotnet 测试用例输出匹配,但预期结果有所不同。例如。就像这里:

  Failed Prime.UnitTests.Services.PrimeService_IsPrimeShould.IsPrime_InputIs2_ReturnTrue [2 ms]
  Error Message:
   2 should be prime
  Expected: True
  Actual:   False
  Stack Trace:
     at Prime.Services.PrimeService.IsPrime(Int32 candidate) in C:\Users\Jens\Documents\Visual Studio 2022\Projects\unit-testing-using-dotnet-test\PrimeService\PrimeService.cs:line 9
   at Prime.UnitTests.Services.PrimeService_IsPrimeShould.IsPrime_InputIs1_ReturnFalse() in C:\Users\Jens\Documents\Visual Studio 2022\Projects\unit-testing-using-dotnet-test\PrimeService.Tests\PrimeService_IsPrimeShould.cs:line 12
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)

第二个匹配抛出异常的测试用例的输出,如下所示:

  Failed Prime.UnitTests.Services.PrimeService_IsPrimeShould.IsPrime_InputIs1_ReturnFalse [2 ms]
  Error Message:
   System.NotImplementedException : Not implemented.
  Stack Trace:
     at Prime.Services.PrimeService.IsPrime(Int32 candidate) in C:\Users\Jens\Documents\Visual Studio 2022\Projects\unit-testing-using-dotnet-test\PrimeService\PrimeService.cs:line 10
   at Prime.UnitTests.Services.PrimeService_IsPrimeShould.IsPrime_InputIs1_ReturnFalse() in C:\Users\Jens\Documents\Visual Studio 2022\Projects\unit-testing-using-dotnet-test\PrimeService.Tests\PrimeService_IsPrimeShould.cs:line 12
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)

这将为两种 dotnet 测试结果提供有效的注释,至少对于实际/预期适合单行的标准测试用例而言。

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