PHPUnitの実行結果(失敗したテスト)をProblem MatcherでPRのdiffに示す

PHPerKaigi 2022でLTしてきます。

fortee.jp

で、Problem Matchersの話に触れるのですが、5分では触れられ無さそうな内容を予め残しておきます。

Problem Matchers?

↓みたいな感じで、PR時のdiff上に「ここが間違っているよ!」を示す仕組み(の1つ)。 f:id:o0h:20220409013844p:plain

ざっくりいうと、

  • GitHub Actionsのアウトプット内容(actionsの実行結果画面って、標準出力的なやつありますよね)からPRのGUIに転記する〜という感じの仕組み
  • 「標準出力をパースするための定義(regexpのパターンや、その反映先のタクソノミーとの関連付け)」を予めどこかに用意しておいて
  • GItHub Actionsのstep上で、特殊な記法(=コマンド)を使って↑の設定ファイルを有効化させる
    • ::add-matcher::{{ 定義ファイルのパス }} という内容をechoする

という流れ。

例えば .github/pm-phpunit.json に定義ファイルを置いた場合、↓みたいなworkflowを作ると動く。
run: echo "::add-matcher::.github/pm-phpunit.json" がミソ

name: phpunit
on: pull_request

jobs:
  phpunit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: latest
          tools: composer, phpunit
      - name: Setup problem matchers for PHPUnit
        run: echo "::add-matcher::.github/pm-phpunit.json"
      - name: Composer install
        run: composer install
      - name: Run PHPUnit
        run: phpunit

詳しい話は↓ github.com github.com

実際の例

例として、こんな感じの定義ファイルを用意してみる。
状況をわかりやすくするために、「patternを1個だけ設定する」ようにしている。その影響で、(実用的では無さそうな気はしつつ)「messageには、ファイル名を入れる」という指定になっている。

f:id:o0h:20220409015529p:plain

これを使わせるためのstepを用意した f:id:o0h:20220409015829p:plain

PHPUnitの失敗したテストがある。
この出力内容を、patternに従ってPR(のFile Changes)に抜き出してくれるようになるのだ f:id:o0h:20220409015420p:plain

じゃーん!

f:id:o0h:20220409015505p:plain

という感じで、「regexpに合致したところから」「パターンにあるグループと、属性(要素)に変換して」「File ChangesのGUI上に表示している」ってな様子が分かる。

PHPUnitのProblem Matcherで、お手軽に使えるやつ

shivammathur/setup-phpもしくはdecnorton/phpunit-problem-matcherを使うのが良い。
php-setupを使っていない(独自のimageをbuildしている、など)の場合は後者一択。
利用方法は、それぞれのREADMEやソースコードを参照。

これら2つも、実際に定義ファイルを用意して利用していることになる。ので、「お手本例」を簡単に見ることが出来る。オープンソースありがと〜〜

github.com github.com

ハマった所

現状、setup-phpの方はいくつかのアサーションに対応していない(ように見える)。要するに、「指定されたregexpで対応できていないものが有る」。

↓これはうまくいく。 f:id:o0h:20220409020628p:plain

↓これらはうまくいかない。 f:id:o0h:20220409020654p:plain f:id:o0h:20220409020709p:plain

setup-phpの方の定義ファイルを見てみると、↓のようにpatternが指定されている。

      "pattern": [
        {
          "regexp": "^\\d+\\)\\s.*$"
        },
        {
          "regexp": "^(.*Failed\\sasserting\\sthat.*)$",
          "message": 1
        },
        {
          "regexp": "^\\s*$"
        },
        {
          "regexp": "^(.*):(\\d+)$",
          "file": 1,
          "line": 2
        }
      ]

紐解くと、

  1. 「数字+閉じ括弧」から始まる行があって
  2. そのすぐ次の行に「Failed+スペース+asserting+スペース+that」を含む行があって
  3. 空白文字のみからなる行があり
  4. 「文字列+コロン+整数文字」の行がある

という感じ。

なので、

  • エラーメッセージがある(失敗例の1枚目には「なんか変だよ!」の出力がある)
  • expect/actualのdiffがある(失敗例の2枚目には不一致文字列の内容の出力がある)

といったケースでは、Problem Matcherがうまく拾ってくれ無さそう。

phpunit-problem-matcherの方ではこれらのケースにも対応できている(ようにみえる)ので、現状ではこちらを利用するのが良いかも知れない。

落ち着いたらPR出そうかなぁと言う気持ち