Github ActionsでPyTest+LocalStackを動かしてテストを自動化する
概要
「機能追加とテストはセットである。テストのないコードはありえない」というお話を何回もしていたのですが「忘れたので別Issueで」とか、そもそもテストを書くという概念がない人が多くてめちゃくちゃ疲弊したので、自動でテストを回してPassしないとマージできないようにしました。
「テストを書きましょう」と個々の意識に任せるのではなく、システム化した方が確実です。
今回はPyTestとLocalStackをGithub Actions上で動かす必要があったのですがそのナレッジを今回ご紹介します。
リポジトリ
今回Github Actionsを検証するにあたり作成したリポジトリです。
ワークフロー
まずはyml全体を書いておきます。
name: test
on:
workflow_dispatch:
push:
branches:
- main
pull_request:
branches:
- main
permissions:
checks: write
pull-requests: write
jobs:
test:
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pipenv'
- name: install pipenv
run: |
python -m pip install --upgrade pip
python -m pip install pipenv
- name: install packages
run: pipenv sync --dev
- name: Cache Docker images.
uses: ScribeMD/docker-cache@0.5.0
with:
key: ${{ hashFiles('docker-compose.yml') }}
- name: start docker compose
run: docker compose up -d
- name: run test
run: pipenv run pytest -q --junit-xml pytest.xml
continue-on-error: true
- name: Publish Test Report
uses: mikepenz/action-junit-report@v5
if: success() || failure()
with:
report_paths: 'pytest.xml'
ポイント
他リポジトリをチェックアウトする時はトークンを発行する
自動的に生成されるGithubトークンはワークフローを起動したリポジトリしかアクセス権限がないので、他のリポジトリを参照したい場合、ランナーとなるマシンにソースコードを持ってくる(チェックアウト)時に認証情報を設定しないとエラーになります。
Github Appsを使って秘密鍵を使ってトークンを取得します。それを使ってチェックアウトします。
Appsを作成したらAPP IDと秘密鍵をリポジトリに登録します。アプリIDはVariablesに、秘密鍵はSecretsに登録しましょう。設定画面から登録できます。
今回の場合、アプリIDはAPP_ID
、秘密鍵はAPP_PRIVATE_KEY
をキーにして登録しています。
設定したらyml上から参照できるようになります。
env:
TARGET_REPO: "first-repo, second-repo"
jobs:
test:
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: create token
id: create-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ vars.APP_ID }} # アプリIDはここ。
private-key: ${{ secrets.APP_PRIVATE_KEY }} # 秘密鍵はここ。
repositories: ${{ env.TARGET_REPO }} # チェックアウトしたいリポジトリ
- uses: actions/checkout@v4
with:
token: ${{ steps.create-token.outputs.token }}
persist-credentials: false
プライベートリポジトリをパッケージとしてインストールする(pip)
上記の方法で生成したトークンを使う事でインストールできます。TARGET_REPO
に対象のリポジトリを含めるのを忘れないように。
pip install git+https://x-access-token:${{ steps.create-token.outputs.token }}@github.com/owner/private-repo.git
例えばプライベートリポジトリで配布されているライブラリに依存しているコードをテストしたい時とかに必要になります。
JUnit形式のサマリーを出す
mikepenz/action-junit-report
を使うと見やすいレポートとどこでテストが失敗したかが確認しやすくなります。PyTestを実行する際、JUnit形式のレポートを出力させて読み込ませることでサマリーを出すことができます。
- name: run test
run: pipenv run pytest -q --junit-xml pytest.xml # `--junit-xml`オプションをつけて結果を出力。
continue-on-error: true # テスト失敗時でも先に進むようにする。テストが失敗するとここで止まってしまうのでサマリーが出ない。
- name: Publish Test Report
uses: mikepenz/action-junit-report@v5
if: success() || failure() # 成功しても失敗しても実行する。
with:
report_paths: 'pytest.xml' # レポートを指定する。
結果はこんな感じ。
使用の際はパーミッションの設定が必要ですので注意して下さい。
TimeOutを設定する
何かしらの理由でランナーがスタックした場合、無駄に時間枠が消費されてしまうので、タイムアウトは必ず設定しておきましょう。デフォルトはなんと6時間!
1つあたりのジョブは1分くらいで終わるとしても、並列で100ジョブ実行すると100分になるので、「短いジョブだから別にいいか」と思わず設定しておきましょう。
jobs:
test:
runs-on: ubuntu-24.04
timeout-minutes: 5 # 5分
steps:
- run: npm run test
キャッシュを効かせる
基本的にはActionsの時間削減ですが、LocalStack用のDockerイメージもキャッシュを効かせることでPull回数制限に引っかからないようにします。
jobs:
test:
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pipenv' # ここ
- name: install pipenv
run: |
python -m pip install --upgrade pip
python -m pip install pipenv
- name: install packages
run: pipenv sync --dev
actions/setup-python
がキャッシュのサポートをしているので自分の環境にあった設定を行います。
Dockerイメージのキャッシュも行います。認証なしユーザーだとPull回数に制限があるのでそこに引っかからないようにキャッシュします。プラススピードアップも狙えます。
jobs:
test:
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pipenv'
- name: install pipenv
run: |
python -m pip install --upgrade pip
python -m pip install pipenv
- name: install packages
run: pipenv sync --dev
- name: Cache Docker images. # これでDockerイメージをキャッシュできます。
uses: ScribeMD/docker-cache@0.5.0
with:
key: ${{ hashFiles('docker-compose.yml') }}
- name: start docker compose
run: docker compose up -d
原理としてはDockerイメージをsaveしておいて、key
が一致したらそれをloadする事でPullせずにDockerイメージを使う事ができます。
key
は各環境に合わせて変更お願いします。
動作検証はPublicリポジトリで
Privateリポジトリは時間枠が決まっているので、あれこれ設定を弄ってはActionsを動かしてを繰り返していると枠を消費します。
なので動作検証はPublicリポジトリでやって、ある程度骨組みができたらPrivateの方に持ってきて、最後はそっちで微調整するという流れがおすすめです。
リポジトリのルールセットについて
ルールセットにステータスチェックを追加するには1回はActionsを回さないといけないのがちょっと注意です。
ポイントとしては、最新コードを含めるチェックを有効にすることです。
最初はここを無効にしていたのですが、featureブランチの状態ではPassしていたのですが、mainブランチにマージした時に失敗する現象が発生しました。
すべてのfeatureブランチがマージした状態のテストが動かないので、最新のコードをfeatureで取り込んできちんとテストがPassすることが確定してからマージするようにします。
まとめ
ここで書いたことは普段からActionsを回している人からすれば新鮮な情報ではないかもしれませんが、何かしら参考になれば幸いです。
Discussion