0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

pytestを使ってみる

0
Posted at

概要

今回はpytestを使ってUnitTestをやってみます。

最低限の使い方のみ記します。
フィクスチャを使ったファイル入出力、モックを使った複数クラスのテストについては次回以降書きます。

それと、pipenvのinstallで一瞬キョドってしまったので
回避方法を簡単に記載しておきます。

テスト対象のコード(呼び出し先)

西暦が閏年かそうでないかをbool値で返すコードをテストします。

check_leaptime.py
def is_leaptime(n: int) -> bool:
    if n % 4 == 0:
        if (n % 100) == 0 and (n % 400) != 0:
            return False
    return True

ここで使用している関数のアノテーションは
引数や返り値の型を指定&可視化する為に記載しています。

メインモジュール(呼び出し元)

テストしたいコードを呼び出します。

test_check_leaptime.py

import pytest
from is_leaptime import is_leaptime 
# pytestは、test_で始まる関数を単体テスト対象として扱う 
def test_is_leaptime(): 
    assert is_leaptime(2020) 
    assert is_leaptime(2024) 
    assert not is_leaptime(2100) 
    assert not is_leaptime(2200)

行頭でimportしたpytestライブラリによって、
test_で始まる関数を単体テスト対象として扱うことが出来ます。
test_is_leaptime()内でassertを使用して、is_leaptimeに引数を渡した結果をデバッグさせてみます。

それでは動かしてみましょう..

仮想環境に接続

そもそも仮想環境を用意していなかったので作成します。
まずpip install pipenvします。
おおっと、WARNINGがでた。:sob:

cmd
pip install pipenv

WARNING: The script virtualenv-clone.exe is installed in 'C:\Users\xxxx\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\Scripts' which is not on PATH. 
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. 
  WARNING: The script virtualenv.exe is installed in 'C:\Users\xxxx\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\Scripts' which is not on PATH. 
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. 
  WARNING: The scripts pipenv-resolver.exe and pipenv.exe are installed in 'C:\Users\xxxx\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\Scripts' which is not on PATH. 
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.

'C:~'のパスをそれぞれPATHに追加しろ、とのことでした。
コマンドプロンプトでPATHを追加→再実施してinstallできました。

続いて、仮想環境に繋ぐにはpipenv shellを叩きます。

接続したら早速テストを動かしてみます。
pytest pyファイルで実行です。

CMD
(pytest_practice-Qnr64jXF) C:\Users\xxxx\Desktop\work\python\pytest_practice>pytest test_check_leaptime.py 
================================================= test session starts ================================================= 
platform win32 -- Python 3.6.8, pytest-6.2.2, py-1.10.0, pluggy-0.13.1 
rootdir: C:\Users\user\Desktop\work\python\pytest_practice 
collected 1 item 
test_check_leaptime.py .                                                                                                  [100%] 
================================================== 1 passed in 0.01s ==================================================

無事にpassしたようです。

今度はcheck_leaptime.pyをいじってerrorを出力させてみます。2020の期待値をFalseとしてみます。

CMD
(pytest_practice-Qnr64jXF) C:\Users\user\Desktop\work\python\pytest_practice>pytest test_check_leaptime.py 
================================================= test session starts ================================================= 
platform win32 -- Python 3.6.8, pytest-6.2.2, py-1.10.0, pluggy-0.13.1 
rootdir: C:\Users\xxxx\Desktop\work\python\pytest_practice 
collected 1 item 
test_check_leaptime.py F                                                                                                  [100%] 
====================================================== FAILURES ======================================================= 
____________________________________________________ test_is_leaptime ____________________________________________________ 
    def test_is_leaptime(): 
        # ↓ 2020から2100に変更 
>       assert is_leaptime(2100) 
E       assert False 
E        +  where False = is_leaptime(2100) 
test_check_leaptime.py:6: AssertionError 
=============================================== short test summary info =============================================== 
FAILED test_check_leaptime.py::test_is_leaptime - assert False 
================================================== 1 failed in 0.04s ==================================================

コードの出力結果とassertに書いた期待値が異なっている事を拾えています。
しかし、この書き方だとErrorとなった箇所から下の行について評価が行われません。

Errorとなる行も含めてすべてのテストを行う

そこでデコレータを使い、以下の用に定義します。

test_check_leaptime.py
import pytest
from is_leaptime import is_leaptime 
@pytest.mark.parametrize(('number', 'expected'), [ 
    (2100, True), 
    (2024, True), 
    (2020, False), 
    (2200, False), 
]) 
def test_is_leaptime(number, expected): 
    assert is_leaptime(number) == expected

デコレータに引数(number,expected)を定義し、西暦(number)を渡したとき、返される期待値(expected)を書きました。

1行目、3行目に(2100, True)・(2020, False)と書いて、errorを拾えるか確認してみます。

CMD
(pytest_practice-Qnr64jXF) C:\Users\xxxx\Desktop\work\python\pytest_practice>pytest test_check_leaptime.py 
================================================= test session starts ================================================= 
platform win32 -- Python 3.6.8, pytest-6.2.2, py-1.10.0, pluggy-0.13.1 
rootdir: C:\Users\xxxx\Desktop\work\python\pytest_practice 
collected 4 items 
test_check_leaptime.py F.F.                                                                                               [100%] 
====================================================== FAILURES ======================================================= 
______________________________________________ test_is_leaptime[2100-True] _______________________________________________ 
number = 2100, expected = True 
    @pytest.mark.parametrize(('number', 'expected'), [ 
        (2100, True), 
        (2024, True), 
        (2020, False), 
        (2200, False), 
    ]) 
    def test_is_leaptime(number, expected): 
>       assert is_leaptime(number) == expected 
E       assert False == True 
E        +  where False = is_leaptime(2100) 
test_check_leaptime.py:13: AssertionError 
______________________________________________ test_is_leaptime[2020-False] ______________________________________________ 
number = 2020, expected = False 
    @pytest.mark.parametrize(('number', 'expected'), [ 
        (2100, True), 
        (2024, True), 
        (2020, False), 
        (2200, False), 
    ]) 
    def test_is_leaptime(number, expected): 
>       assert is_leaptime(number) == expected 
E       assert True == False 
E        +  where True = is_leaptime(2020) 
test_check_leaptime.py:13: AssertionError 
=============================================== short test summary info =============================================== 
FAILED test_check_leaptime.py::test_is_leaptime[2100-True] - assert False == True 
FAILED test_check_leaptime.py::test_is_leaptime[2020-False] - assert True == False 
============================================= 2 failed, 2 passed in 0.11s =============================================

期待通り、すべてのテストを流すことが出来ました。

参考にさせて頂いたサイト:bow:

https://rinatz.github.io/python-book/ch08-02-pytest/
https://gammasoft.jp/blog/python3-function-annotations/

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?