BFT名古屋 TECH BLOG

日々の業務で得た知識を所属するエンジニアたちがアウトプットしていきます。

【Python】【pytest】parametrizeでテストコードを簡略化!

こんにちは!
目指せ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.py17行でありました。

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の利点ではないかと思います。
今回の記事が参考になれば幸いです。
最後までご覧いただきありがとうございました。