LoginSignup
44
40

More than 1 year has passed since last update.

GitHub Actionsを用いた自動テストの実行と結果集計

Last updated at Posted at 2021-09-17

1. はじめに

GitHub Actionsを用いて自動テストの実行と結果の集計を行う方法を説明します。

具体的には、ソースコードがGitHubへpushされたタイミングで、pythonで書かれたテストをpytestを使って実行し、GitHub上に下図のサマリを表示します。

summary1.png

今回、GitHub Actionsを初めて使ったので、学習のためにGitHub Actionsの基本についても触れています。

2. GitHub Actionsとは

GitHubのCI/CDツール。

push, pull requestなどのGiHub上のアクティビティやスケジュールした時間、外部イベントをトリガーとして、ワークフローを作成できます。

特徴

  • Linux, macOS, Windowsすべてのコンテナに対応
  • Node.js, Python, Java, Rubyなど、様々な言語に対応
  • 複数のジョブを並行してビルド可能

用語

  • ワークフロー
    • トリガーと1つ以上のジョブで構成される手順
    • リポジトリ内の.github/workflowsディレクトリにYAML形式で定義
  • イベント
    • ワークフローをトリガーする特定のアクティビティ
    • 外部イベントをトリガーしたい場合は、webhookを使用する
  • ジョブ
    • 一連のステップ
    • 1つのワークフローに複数のジョブが存在する場合は、並行して実行される
  • ステップ
    • ジョブでコマンドを実行できる個々のタスク
    • アクションまたはシェルコマンドで設定できる
  • アクション
    • ワークフローを作成するための最小単位のコマンド
    • 独自のアクションを作成することも、オープンソースのアクションを使用することも可能
  • 成果物(Artifacts)
    • ワークフロー実行中に生成されるファイル

ワークフローの構造

GitHub Docsにあるサンプルを用いて各項目を説明します。それぞれの詳細は、GitHub Actionsのワークフロー構文が詳しいです。

name: learn-github-actions
on: [push]
jobs:
  check-bats-version:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v1
      - run: npm install -g bats
      - run: bats -v
項目名 説明
name: ワークフローの名前。GitHubのActionsに表示される。なんでもよい
on: 必須。トリガーのイベント。上の例ではpushする度にジョブが実行される
jobs: ワークフローで実行されるジョブのグループ。複数のジョブの集合
check-bats-version: ジョブのID。英字または_で始める必要があり、英数字と-_しか使用できない
runs-on 必須。ジョブが実行されるマシンの種類。OSバージョンを指定することもできる
steps: ジョブで実行されるステップのグループ
- uses: 使用するアクション
- run: 実行するシェルコマンド

以下の階層をイメージするとよいと思います。

name: ワークフローの名前
on: トリガーのイベント
jobs:
  ジョブのID
    runs-on: ジョブが実行されるマシンの種類
    steps:
        - uses: アクション
        - run: シェルコマンド

ワークフローの作り方

ワークフロー(YAMLファイル)を作成するには大きく2つの方法があります。完成するファイルは同じなので、使いやすい方でOKです。

方法①テキストエディタ

VSCodeなどのテキストエディタでリポジトリ内の.github/workflowsディレクトリにYAMLファイルを作成する方法。VSCodeの場合、GitHub Actionsという拡張機能を使うとよい。

方法②GitHub

GitHubのActionsタブ>「New workflow」>「set up a workflow yourself」で新規作成。テンプレートに沿って作成することができ、下図のMarketplaceからアクションを検索しやすい。

market.png

3. 自動テストの実行と結果の集計

今回は、自動テスト(pytest)の実行と結果の集計を行うワークフロー(YAMLファイル)を作成します。

大まかな流れ

  1. トリガーの指定
  2. ジョブの条件
  3. python環境のセットアップ
  4. 自動テストを実行する
  5. 自動テストの結果をGitHub上に表示する
  6. ワークフローの実行と確認

先に、YAMLファイルの完成版は以下の通り。各トリガーやステップの詳細は後述します。

action.yml
name: Run pytest
on: [push]

jobs:
  pytest:
    runs-on: ubuntu-latest

    steps:
      # リポジトリをチェックアウト
      - name: Checkout
        uses: actions/checkout@v2

      # Pythonの環境をセットアップ
      - name: Set up Python 3.7
        uses: actions/setup-python@v2
        with:
          python-version: 3.7

      # pytestをインストール
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install pytest

      # pytest -> JUnit xml形式で結果を出力
      - name: PyTest
        run: |
          python -m pytest test --junit-xml results/pytest.xml
        continue-on-error: true

      # テスト結果の表示
      - name: Upload Unit Test Results
        if: ${{ always() }}
        uses: actions/upload-artifact@v2
        with:
          name: Unit Test Results (Python 3.7)
          path: results/*.xml

      - name: Download Artifacts
        if: success() || failure()
        uses: actions/download-artifact@v2
        with:
          path: artifacts

      - name: Publish Unit Test Results
        uses: EnricoMi/publish-unit-test-result-action@v2
        with:
          junit_files: artifacts/**/*.xml

※2022/10/21 filesだとWarningが出たのでjunit_filesに修正。

トリガーの指定

pushしたタイミングで自動テストを実行したいので、pushを指定します。

on: [push]

他にも、

  • Pull Requestのタイミング
  • Pull Request Reviewのタイミング
  • ブランチの指定
  • タグの指定

などをトリガーにできます。その他のイベントはワークフローをトリガーするイベントを参照。

# 例:mainブランチでpushもしくはPull Requestが行われたタイミングで実行
on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

ジョブの条件

ジョブ(pytest)の実行マシンを指定します。今回は、ubuntu-latestを使用します。macOSWindowsも使用でき、その場合は「Publish Unit Test Results」のアクションの書き方が異なります。

jobs:
  pytest:
    runs-on: ubuntu-latest

python環境のセットアップ

ここからはステップの記述です。

自動テストを実行するためにpython環境をセットアップします。今回はpython-version: 3.7を使っています。

使用するアクション

  • Checkout
    • ワークフローがリポジトリにアクセスできるように、リポジトリをチェックアウトする
  • Setup Python
    • python環境をセットアップする
steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Set up Python 3.7
      uses: actions/setup-python@v2
      with:
        python-version: 3.7

    - name: Install dependencies
      run: |  # コマンドを複数行記述したい場合は「|」を使う
        python -m pip install --upgrade pip
        pip install pytest

自動テストを実行する

自動テストの実行とJUnit XML形式の結果の出力をコマンドで記述します。また、ステップが失敗しても次のジョブへ進むために、continue-on-error: trueを設定します。

    - name: PyTest
      run: |
        python -m pytest test --junit-xml results/pytest.xml
      continue-on-error: true

自動テストの結果をGitHub上に表示する

自動テストの結果をGitHubのArtifacts上にアップロードし、結果を表示します。

使用するアクション

      # テスト結果の表示
      - name: Upload Unit Test Results
        if: ${{ always() }}
        uses: actions/upload-artifact@v2
        with:
          name: Unit Test Results (Python 3.7)
          path: results/*.xml

      - name: Download Artifacts
        if: success() || failure()
        uses: actions/download-artifact@v2
        with:
          path: artifacts

      - name: Publish Unit Test Results
        uses: EnricoMi/publish-unit-test-result-action@v2
        with:
          junit_files: artifacts/**/*.xml

ArtifactsはActionsタブの以下から取得することができます。

artifacts.png

ワークフローの実行と確認

何かしら変更を加えてpushすると、ワークフローが実行されます。

実行したワークフローは、GitHubのActionsタブまたはcommit履歴から閲覧できます。

▼GitHubのActionsタブ(コミットメッセージは適当です)

workflows.png

ワークフローを選択すると、実行結果のサマリを確認することができます。

summary2.png

4. Tips: Selenium + pytestを実行する

Seleniumを使った自動テストを実行したい場合も前述のワークフローを流用できますが、2つポイントがあります。

  • webdriver_managerを用いて、ブラウザバージョンに対応するdriverを自動で適用する
  • Chromeを"--headless"モードで実行する

まず、Install dependenciesのステップに以下のコマンドを追加し、webdriver-managerをインストールします。

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install pytest
        pip install webdriver-manager

テストスクリプト内での使い方は次の通り。

# Selenium 4
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager

options = Options()
options.headless = True
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
# Selenium 3の場合
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument("--headless")
driver = webdriver.Chrome(ChromeDriverManager().install(), chrome_options=options)

"--headless"をoptionに設定せずにGitHub Actionsを実行すると、次のエラーメッセージが表示されてしまいます。

selenium.common.exceptions.WebDriverException: Message: unknown error: Chrome failed to start: exited abnormally.

あとは通常通りGitHub Actionsを実行すればOKです。

5. 所感

サードパーティ含むアクションのライブラリが充実していて、思ったよりもゴリゴリコマンドを書く必要がない印象を受けました。また、GitHub Actionsに関するドキュメントが整備されていたのがありがたかったです。

CI/CDツールといえばJenkinsやCircleCIのイメージが強かったのですが、GitHubでソースコード管理をしている場合は十分候補になりそうです。

6. 参考

44
40
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
44
40