5分でできるGitHub Actionsを用いた自動テスト


## 目次
1. [はじめに](#はじめに)  
2. [事前準備](#事前準備)  
3. [ディレクトリ構成例](#ディレクトリ構成例)  
4. [サンプルコード例](#サンプルコード例)  
5. [ワークフローファイルの作成](#ワークフローファイルの作成)  
6. [実行例](#実行例)  
7. [まとめ](#まとめ)  
8. [参考にしたもの](#参考にしたもの)  

## はじめに
コード品質を維持するためにはテストが不可欠ですが、手動での実行は手間がかかります。GitHub Actionsを使えば、`push`時や`pull_request`時に自動でテストを実行し、開発フローにシームレスに組み込めます。

本記事では5分でできるGitHub Actionsによる自動テスト設定方法を紹介します。KaggleやAI開発プロジェクトに取り組む際にも有用です。これで新機能開発時も、プッシュ時やプルリクエスト前に自動テストを回して品質を確保できます。

:::note info
たった5分の手間が、後々のデバッグ時間を大幅に削減します！
:::


## 事前準備
1. **GitHubリポジトリの用意**：対象となるPythonプロジェクトがGitHub上にあること  
2. **テストコードの用意**：`pytest`で動くテストがあること  
3. **requirements.txtの用意**: `requirements.txt`に`pytest`など必要なモジュールが記載されていること 
    ```requirements.txt
    -e .
    pytest
    （他のモジュールも記載）
    ```
4. **pyproject.tomlによる設定（任意）**: `pyproject.toml`で`pytest`のオプションを指定し、`pythonpath`を設定可能（`src`ディレクトリをモジュール探索パスに含めるなど）
    ```pyproject.toml
    [tool.pytest.ini_options]
    pythonpath = ["src", "tests"]
    ```

ローカルでテストが通る状態であれば、あとはActions設定を追加するだけでOKです。
下記はローカルで`pytest`を実行した際の例です：

```bash
$ pytest
================================================================================ test session starts ================================================================================
:
:
collected 3 items                                                                                                                                                                    

tests\test_main.py ..                                                                                                                                                          [ 66%] 
tests\mod\test_module_1.py .                                                                                                                                                   [100%] 

================================================================================= 3 passed in 0.03s ================================================================================= 

```

## ディレクトリ構成例

以下は、典型的なディレクトリ構成例です。

```
.
├── src
│   ├── __init__.py
│   ├── main.py
│   └── mod
│       ├── __init__.py
│       └── module_1.py
├── tests
│   ├── __init__.py
│   ├── test_main.py
│   └── mod
│       ├── __init__.py
│       └── test_module_1.py
├── requirements.txt
├── pyproject.toml
└── .github
    └── workflows
        └── test.yml
```

ソースコードは下記のGitHubレポジトリーから入手可能です：

https://github.com/Isaka-code/ci-cd-in-5minutes

## サンプルコード例

### プロダクトコード例 (`src`配下)

**`src/main.py`**  
```python
from src.mod import module_1


def main(a: int, b: int) -> int:
    return a + b


def hello() -> str:
    return module_1.hello()
```

**`src/mod/module_1.py`**  
```python
def hello() -> str:
    return "Hello from module_1"
```

### テストコード例 (`tests`配下)

**`tests/test_main.py`**  
```python
def test_main():
    from src.main import main

    assert main(1, 2) == 3


def test_hello():
    from src.mod import module_1

    assert module_1.hello() == "Hello from module_1"
```

**`tests/mod/test_module_1.py`**  
```python
def test_hello():
    from src.mod import module_1
    assert module_1.hello() == "Hello from module_1"
```

`pytest`実行時、`tests`ディレクトリ以下にある`test_`で始まるファイルが自動的に読み込まれ、`test_`で始まる関数がテストとして実行されます。


:::note info
テスト関数内でインポートしているのは、テストエラーが起きた際にエラーログがその関数単位で明確になるからです。pytestにおける御作法の一つになります。
:::



## ワークフローファイルの作成
プロジェクトルートに`.github/workflows`ディレクトリを作成し、`test.yml`ファイルを配置します。  
以下は`main`ブランチと`feature/`で始まるブランチへの`push`、およびそれらブランチをターゲットとした`pull_request`の際にPython 3.10でテストを実行する例です。


```test.yml
name: Run Tests on Push or PR

on:
  push:
    branches: [ main, 'feature/*' ]
  pull_request:
    branches: [ main, 'feature/*' ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Check out repo
        uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.10'  

      - name: Install dependencies
        run: |
          pip install -r requirements.txt

      - name: Run tests
        run: pytest
```

### ポイント
- `on:`セクションで`push`と`pull_request`を指定。これにより、指定のブランチへコードを`push`した時と、そのブランチに対するPRが作成・更新された時両方でテストが走る。  
- Pythonバージョンは`3.10`でKaggle環境と合わせ、再現性を高める。


## 実行例
1. `feature/*`ブランチにローカルで変更を加え、`push`すると、Actionsでテストが自動実行  
2. 同ブランチから`main`へのプルリクエストを作成すると、PRページ上でテスト結果が確認可能。マージ前にテスト合格を一目で確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627015/655064b7-e6b8-0e07-1c25-d7a962b2ba72.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627015/76fbc9ae-ac0d-3497-9ec6-05fdc65157cc.png)

これにより、コード品質を常に確認しながら安心して開発を進められます。








## まとめ
- GitHub Actionsは、`push`や`pull_request`時の自動テスト実行を簡単に実現  
- YAMLファイルと`pytest`で、品質チェックを自動化  
- Python 3.10指定でKaggleと同等環境を再現し、MLプロジェクトでの利便性向上

5分でできる自動テストの導入で、コード品質向上と開発効率UPをぜひ体験してみてください。



## 参考にしたもの

https://docs.github.com/actions

https://docs.pytest.org/

https://docs.pytest.org/en/latest/explanation/goodpractices.html#test-package-name

https://qiita.com/ShortArrow/items/32fa54b2c32e09355fed

https://poota.net/archives/444

https://helve-blog.com/posts/python/pytest-directory/

https://zenn.dev/panyoriokome/articles/f34ae72cc33150