もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

GithubActions で phpunit の並列実行

はじめに

こんばんは。

今回もテスト系の備忘録です。

以前 CircleCI でテストの並列実行を行った記事を書きました。

kojirooooocks.hatenablog.com

今回はこれのgithub action版です。

本題

CircleCIでは circleci test globcircleci test split みたいな並列実行を簡単に実装できるような機能が提供されてました。

github actionsでは似たような機能がなかったので自前実装で実装しました。

肝となる部分はこちらのコードを使わせてもらいました。ありがとうございます!!

gist.github.com

github actionのコードはこちら

.github/workflows/unittest.yml

name: unit test
on:
  push:

jobs:
  test:
    runs-on: ubuntu-20.04
    strategy:
      fail-fast: false
      matrix:
        parallelism: [5]
        id: [0,1,2,3,4]

    steps:
      - name: Checkout
        uses: actions/checkout@master

      - name: Install Dependencies
        run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist

      - name: Execute Test
        run: |
          find src/ -name '*Test.php' | sort | awk "NR % ${{ matrix.parallelism }} == ${{ matrix.id }}" | xargs php ./bin/create_ci_phpunit_xml.php
          ./vendor/bin/phpunit --configuration /tmp/ci_phpunit.xml

phpunitのymlを作成するコードはこちら

bin/create_ci_phpunit_xml.php

<?php

$baseDir = realpath('./');
$files   = array_slice($argv, 1);
$xmlFileStringData = [];
foreach ($files as $file) {
    $xmlFileStringData[] = "<file>{$baseDir}/{$file}</file>";
}
$testFileString = implode("\n", $xmlFileStringData);
$template = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true" bootstrap="{$baseDir}/bootstrap.php">
    <testsuites>
        <testsuite name="Test Case">
            {$testFileString}
        </testsuite>
    </testsuites>
</phpunit>
XML;

file_put_contents("/tmp/ci_phpunit.xml", $template);

キモとなるのは awkのNR変数です。

NR変数は処理中の行数を取得できるので、現在処理中の行数と、並列max数の余りを求めて、それがそれぞれのjobIDと一致していれば、それぞれのjobに振り分けるという感じ...だと思います。

it-ojisan.tokyo

f:id:kojirooooocks:20210303015323p:plain

parallelism で設定している 数分のjobが実行されています!

f:id:kojirooooocks:20210303015338p:plain

f:id:kojirooooocks:20210303015349p:plain

また、実行しているjobの番号がそれぞれ変わっているのもわかります。

終わりに

circleci test split --timing とかはまたひねりが必要な感じだと思います。

タイミングはgithub actionsではどうすればよいのかな?

現場からは以上です。