こんにちは!
目指せPythonマスター!Python歴2年目のBFT名古屋支店のザき男です。
2022年はpytestの年でした。ということで、今回を含め数回に分けて、pytestの知って得する使い方についてご紹介していきます。
今回はテストコードを簡略化する仕組みのparametrizeについてご紹介します。
pytestについてはこちらを参考にしてください。
目次
parametrizeとは
概要
parametrizeとは、指定した値をパラメータ(配列のような形式)としてテストコードに渡すpytestの仕組みになります。
# parametrizeのサンプル parametrize_sample = [(1.71, 64, "ふつう")] # ←配列のようなデータが入るイメージ。
parametrizeを利用することで、1つのテスト関数で、複数のテストパターンを扱うことができます(テストコード作成の簡略化)。
また、冗長なコードを簡潔なコードとして表現できるため、そもそものテストコード作成に要する時間を短縮することができます。
また、手作業の介入を減らすことができるため、作業ミスを減らすことができます。
実践
ここからはparametrizeの実際の使い方について説明していきます。
今回はBMIをサンプルに説明します。
※BMI…「Body Mass Index」の略で、肥満度を表す指数です。
実施環境
●Python 3.8.10
●pytest 6.2.5
ディレクトリ構成
bmi ├ bmi.py…テスト対象コード ├ test_bmi.py…テストコード
下準備
BMIの計算式 : BMI = 体重(kg) / (身長(m))²
●BMIの判定
BMI | 判定 |
---|---|
0~18.5未満 | やせがた |
18.5~25未満 | ふつう |
25〜30未満 | ややぽっちゃり |
30〜35未満 | ぽっちゃり |
35〜40未満 | ややかっぷくがいい |
40以上 | かっぷくがいい |
テスト対象コード
※サンプルコードなのでゼロ除算や例外などの考慮は割愛してます。
●bmi.py
def calculate_bmi(height, weight): bmi = weight / (height*height) if 0 < bmi < 18.5: return "やせがた" elif 18.5 <= bmi < 25: return "ふつう" elif 25 <= bmi < 30: return "ややぽっちゃり" elif 30 <= bmi < 35: return "ぽっちゃり" elif 35 <= bmi < 40: return "ややかっぷくがいい" elif bmi >= 40: return "かっぷくがいい" else: return False
テストコードの作成
今回はBMIを判定していきます。
(テスト対象コードの分岐を網羅するようテストパラメータを用意します。)
●test_bmi.py
import pytest import bmi # height, weight, expectations のリスト test_parameters = [ (1.71, 64, "ふつう"), (1.72, 53, "やせがた"), (1.8, 100, "ぽっちゃり"), (4.8, 900, "ややかっぷくがいい"), (2.5, 250, "かっぷくがいい"), (1.3, 45, "ややぽっちゃり"), (1.5, 0, False) ] @pytest.mark.parametrize("height, weight, expectations", test_parameters) def test_calculate_bmi(height, weight, expectations): assert (bmi.calculate_bmi(height, weight)) == expectations
pytest実行&結果確認
pytestコマンドでテストを実行します。
※実行する際はカレントディレクトリが「bmi」の状態にディレクトリ移動しておく必要があります。
以下の例では詳細な結果を表示するための -v
オプションを使用しています。
7ケース分のテストが実行され、「7 passed」だったので、全てのテストが成功しました。
$ pytest -v test_bmi.py ============================================ test session starts ============================================ platform win32 -- Python 3.8.10, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- C:\Users\BFTUser\AppData\Local\Programs\Python\Python38\python.exe cachedir: .pytest_cache rootdir: C:\Users\BFTUser\python\bmi plugins: cov-4.0.0, env-0.6.2, flakes-4.0.5, forked-1.4.0, mock-3.10.0, xdist-2.5.0 collected 7 items test_bmi.py::test_calculate_bmi[1.71-64-\u3075\u3064\u3046] PASSED [ 14%] test_bmi.py::test_calculate_bmi[1.72-53-\u3084\u305b\u304c\u305f] PASSED [ 28%] test_bmi.py::test_calculate_bmi[1.8-100-\u307d\u3063\u3061\u3083\u308a] PASSED [ 42%] test_bmi.py::test_calculate_bmi[4.8-900-\u3084\u3084\u304b\u3063\u3077\u304f\u304c\u3044\u3044] PASSED [ 57%] test_bmi.py::test_calculate_bmi[2.5-250-\u304b\u3063\u3077\u304f\u304c\u3044\u3044] PASSED [ 71%] test_bmi.py::test_calculate_bmi[1.3-45-\u3084\u3084\u307d\u3063\u3061\u3083\u308a] PASSED [ 85%] test_bmi.py::test_calculate_bmi[1.5-0-False] PASSED [100%] ============================================= 7 passed in 0.15s =============================================
parametrizeを利用しない場合との比較
parametrizeの場合
上記の test_bmi.py
は17行でありました。
parametrizeを利用しない場合
下記のparametrizeを利用しない場合のテストコードは、上記のparametrizeを利用した場合のテストコードと全く同じテストをしていますが44行もあり、冗長なコードであることが分かります。
●test_bmi.py
import pytest import bmi def test_calculate_bmi1(): height = 1.71 weight = 64 expectations = "ふつう" assert (bmi.calculate_bmi(height, weight)) == expectations ''' 省略 ''' def test_calculate_bmi7(): height = 1.5 weight = 0 expectations = False assert (bmi.calculate_bmi(height, weight)) == expectations
まとめ
parametrizeを利用することで、テストコード作成を簡略化できることがお分かりいただけたかと思います。
また、簡略化することによって、テストコード作成に要する時間の短縮や人的ミスの発生を防ぐことに繋がります。
本文中では触れませんでしたが、その他に、テストコードの見易さやテストコードの修正・変更が容易という点もparametrizeの利点ではないかと思います。
今回の記事が参考になれば幸いです。
最後までご覧いただきありがとうございました。