LoginSignup
10
6

More than 3 years have passed since last update.

Pythonでユニットテスト書いてみよう-3

Posted at

概要

Pythonのユニットテストについて以下の2つ標準機能について紹介しました。
1. unittest
2. doctest

今回はpytestフレームワークを紹介します。

pytest

公式サイトには以下の様に書いてあります。

pytest is a framework that makes building simple and scalable tests easy. Tests are expressive and readable—no boilerplate code required. Get started in minutes with a small unit test or complex functional test for your application or library.

要約すると、
①シンプルでスケーラブルなテストフレームワークだよ
②読みやすいよ
③小規模なテストから複雑なテストもできるよ

インストール

unittestとdoctestと違って、Pythonインストールした時点では入ってこないため、別当インストールする必要があります。以下のコマンドでインストールができます。

pip install pytest

正常にインストール出来たら、バージョンを確認すると以下のように表示されます。

# pytest --version
This is pytest version 5.2.1, imported from /usr/local/lib/python3.6/site-packages/pytest.py

書き方

pytestの書き方はとても簡単です。テスト用の関数を用意し、その中にテストケースを記述するのみです。

# テスト対象の関数
def func_XXX():
    処理の記述

# 1. テスト用の関数の作成
def test_func_XXX():
    # 2. テストケースを記入
    assert func_XXX(2) == 6

Let's Code

では、実際にテストを実行してみましょう。
まずは、ワークフォルダーを作成し、その中にtest_sample1.pyを作成してください。「test_sample1.py」の中身を以下にしてください。

test_sample1.py
def add(num1, num2):
    """
    引数として受けた数値を足し算し、
    その結果を返す。
    """
    return num1 + num2

def test_add():
    """
    2 + 3 = 6
    """
    assert add(2,3) == 6

ターミナルから上記で作ったワークフォルダーに移動し、pytestを入力し、ENTERキーを押してください。以下のようにテストが失敗したメッセージが表示されます。

# pytest
===================================== test session starts =====================================
platform linux -- Python 3.6.9, pytest-5.2.1, py-1.8.0, pluggy-0.13.0
rootdir: /home/dakc
collected 1 item

test_sample1.py F                                                                       [100%]

========================================== FAILURES ===========================================
__________________________________________ test_add ___________________________________________

    def test_add():
        """
        2 + 3 = 6
        """
>       assert add(2,3) == 6
E       assert 5 == 6
E        +  where 5 = add(2, 3)

test_sample1.py:12: AssertionError
====================================== 1 failed in 0.02s ======================================
#

pytestを入力するだけでテストが実行されますが、ファイルの名前が影響しています。例えば、上記のファイルの名前を「sample.py」に変えれば、テストが実行されません。

# pytest
===================================== test session starts =====================================
platform linux -- Python 3.6.9, pytest-5.2.1, py-1.8.0, pluggy-0.13.0
rootdir: /home/dakc
collected 0 items

==================================== no tests ran in 0.01s ====================================

テストを実行するには以下の注意を払う必要がある。
1. ファイル名をtest_XXXにする
2. ファイル名をXXX_testにする
3. 明示的にファイルを指定する

上記の例のtest_sample1.pyは、「1.」のtest_XXXに該当します。
また、sample.pyの場合はエラーになりましたが、「3.」のようにpytest sample.pyを実行すれば、テストが実行されます。

まとめてテスト

複数テストファイルをまとめてテストしたいケースがあります。その場合の手順を紹介します。
先ほど作ったワークフォルダーに「test_sample2.py」を作成し、以下の内容にしてください。

test_sample2.py
def add(num1, num2):
    """
    引数として受けた数値を足し算し、
    その結果を返す。
    """
    return num1 + num2

def test_add():
    """
    2 + 3 = 5
    """
    assert add(2,3) == 5

(違いは今回のテストケースが正しい内容「2+3=5」になっただけです。)
そして、pytestを実行してください。

# pytest
===================================== test session starts =====================================
platform linux -- Python 3.6.9, pytest-5.2.1, py-1.8.0, pluggy-0.13.0
rootdir: /home/dakc
collected 2 items

test_sample1.py F                                                                       [ 50%]
test_sample2.py .                                                                       [100%]

========================================== FAILURES ===========================================
__________________________________________ test_add ___________________________________________

    def test_add():
        """
        2 + 3 = 6
        """
>       assert add(2,3) == 6
E       assert 5 == 6
E        +  where 5 = add(2, 3)

test_sample1.py:12: AssertionError
================================= 1 failed, 1 passed in 0.16s =================================
#

出力内容通り、2つのテストケースの中で一つが失敗し、一つが成功した事が分かります。
test_sample1.pyの12行のテストが失敗した事がわかります。

一回の実行で、カレントディレクトリのすべてのファイルを一斉にテストしてくれます。

補足-1

unittestとdoctestと同様に、ターミナルからpython -m pytest ファイル名を実行する事でユニットテストができます。test_XXXまたは、XXX_testにファイル名を揃えていれば、最後のファイル名省略することができます。

補足-2

pytestにはたくさんの便利な機能ありますが、その中の一つ「mark」について紹介します。たくさんのテストケースの中から特定の分だけテストしたい時に大変役に立つ機能です。関数に@pytest.mark.マーク名デコレートする事でこの機能を利用できます。

sample.py

import pytest
def add(num1, num2):
    """
    引数として受けた数値を足し算し、
    その結果を返す。
    """
    return num1 + num2

@pytest.mark.success
def test_add_success():
    """
    2 + 3 = 5
    """
    assert add(2,3) == 5

@pytest.mark.failure
def test_add_failure():
    """
    2 + 3 = 6
    """
    assert add(2,3) == 6

上記の例では、「add」関数の成功と失敗のテストケースを記述した関数が2つあります。成功するテストケースを書いた関数に「success」マークをつけました。そして、失敗するテストケースの関数には「failure」マークをつけました。

例えば、「add」の中身の一部を変える必要があり、その影響が「test_add_success」のみにあるとします。そのために、「test_add_success」関数だけテストしたい場面が出てきたとします。このような時はpytestのマーク機能を使います。
以下のコマンドで特定のマークのみテストします。
pytest ファイル名 -m マーク名


# pytest sample.py -m success
===================================== test session starts =====================================
platform linux -- Python 3.6.9, pytest-5.2.1, py-1.8.0, pluggy-0.13.0
rootdir: /home/dakc
collected 2 items / 1 deselected / 1 selected

sample.py .                                                                             [100%]

====================================== warnings summary =======================================
/usr/local/lib/python3.6/site-packages/_pytest/mark/structures.py:325
  /usr/local/lib/python3.6/site-packages/_pytest/mark/structures.py:325: PytestUnknownMarkWarning: Unknown pytest.mark.success - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html
    PytestUnknownMarkWarning,

/usr/local/lib/python3.6/site-packages/_pytest/mark/structures.py:325
  /usr/local/lib/python3.6/site-packages/_pytest/mark/structures.py:325: PytestUnknownMarkWarning: Unknown pytest.mark.failure - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html
    PytestUnknownMarkWarning,

-- Docs: https://docs.pytest.org/en/latest/warnings.html
========================= 1 passed, 1 deselected, 2 warnings in 0.13s =========================

最後に

Pythonのユニットテストについて3回に分けて三つの方法を使って紹介しました。
1. 第1回目:unittestについて
2. 第2回目:doctestについて
3. 第3回目:pytestについて
何かの参考になれば幸いです。

10
6
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
10
6