🙌

初めて pytest でテストを書いてみた

2023/08/19に公開

イントロダクション

pytest とは

pytest は、Python のテストフレームワークであり、Python プロジェクトのテストを効率的に行うための強力なツールです。

  • 簡単なテスト記述
    pytest は、テストケースを記述するために簡潔で自然な構文を提供します。テスト関数は通常、test_ で始まる関数名を持ち、アサーションを使用してテスト条件を表現します。

  • 自動テスト検出
    pytest は、テスト関数を自動的に検出します。テストファイルやテストスイートを手動で登録する必要はありません。テストケースがコンフォーミングな名前規則に従っていれば、自動的に実行されます。

  • アサーションの使用
    テストケース内でアサーションを使用して、期待結果と実際の結果を比較します。アサーションが失敗した場合、pytest は失敗したテストケースの詳細情報を提供します。

環境のセットアップ

  • Python 環境の構築
    今回は省略します。

  • pytest のインストール

    pip install pytest
    
  • poetry の設定
    通常なら poetry add でインストールしますが、pytest は開発環境でのみ使用するため、--dev オプションを付けてインストールします。

    poetry add pytest --group dev
    
  • テスト対象のプロジェクトのセットアップ

    pytest_demo
    ├── README.md
    ├── myapp
    | └── prime.py        <- テスト対象の関数
    ├── tests
    | └── test_prime.py   <- テストコード
    ├── poetry.lock
    └── pyproject.toml
    

基本的なテストを書く

  • テストケースをパスさせるための最小限のコードを書きます

素数判定の関数を書く

# myapp/prime.py

def is_prime(n: int) -> bool:
    """
    与えられた数値が奇数であるかを判定する関数

    Args:
        n: 判定する数値

    Return:
        奇数であればTrue、偶数であればFalse

    """

    if n <= 1:
        return False

    if n == 2:
        return True

    if n % 2 == 0:
        return False

    i = 3

    while i * i <= n:
        if n % i == 0:
            return False

        i += 2

    return True

テストケースを書く

# tests/test_prime.py

from myapp.prime import is_prime


def test_is_prime():
    assert not is_prime(1)
    assert is_prime(2)
    assert is_prime(3)
    assert not is_prime(4)
    assert is_prime(5)
    assert not is_prime(6)
    assert is_prime(7)
    assert not is_prime(8)
    assert not is_prime(9)
    assert not is_prime(10)

テストの実行

  • テストが通ることを確認する
pytest tests/test_prime.py

結果が返ってきます

============= test session starts =============
platform darwin -- Python 3.10.8, pytest-7.4.0, pluggy-1.2.0
rootdir: ~/pytest_demo
collected 1 item

tests/test_prime.py .                   [100%]

============== 1 passed in 0.00s ==============

コードを変えてみる

csv ファイルを読み込んで電話番号を抽出する関数を書く

# myapp/find_phone_numbers.py

import csv
import re


def find_phone_numbers(file_path: str) -> list:
    """
    ファイルを読み込んで、電話番号を抽出する関数

    Args:
        file_path: ファイルパス

    Return:
        電話番号のリスト

    """
    phone_numbers = []
    with open(file_path, "r") as file:
        reader = csv.reader(file)
        for row in reader:
            for item in row:
                matches = re.findall(r"\d{2,4}-\d{2,4}-\d{4}", item)
                phone_numbers.extend(matches)
    return phone_numbers

csv ファイルを作成しつつ、テストケースを書く

# tests/test_find_phone_numbers.py

import csv

from myapp.fine_phone_numbers import find_phone_numbers


# find_phone_numbers() 関数のテスト関数
def test_find_phone_numbers():
    data = [
        ["1", "Alice", "female", "080-1234-5678"],
        ["2", "Bob", "male", "090-2345-6789"],
        ["3", "Charlie", "male", "070-3456-7890"],
    ]

    with open("./data/test_find_phone_numbers.csv", "w", newline="") as file:
        writer = csv.writer(file)
        writer.writerow(["ID", "name", "sex", "phone numbers"])
        writer.writerows(data)

    phone_numbers = find_phone_numbers("./data/test_find_phone_numbers.csv")
    assert phone_numbers == ["080-1234-5678", "090-2345-6789", "070-3456-7890"]

  • テストケースが引き続き通ることを確認
pytest tests/test_find_phone_numbers.py

無事、csv ファイルから電話番号を抽出できたようです。

まとめと次のステップ

今回はかなり簡単なテストを書いてみました。
実際は、例外処理のテストや mocker を使ったテストなどかなり複雑なことが出来ます。
次回は、より複雑なテストを書いてみたり、テストのレポートを見てみたりしてみたいと思います。

参考文献とリソース

GitHubで編集を提案

Discussion