【Python】pytest でユニットテスト

pytest でユニットテスト

pytestをインストールします。

$ uname -v
Darwin Kernel Version 14.0.0: Fri Sep 19 00:26:44 PDT 2014; root:xnu-2782.1.97~2/RELEASE_X86_64
$ python --version
Python 2.7.11 :: Anaconda custom (x86_64)
$ pip install pytest

テスト対象のコードを書きます。例として, 時刻を表す文字列 ‘%Y-%m-%dT%H:%M:%S’ の時刻の差分を計算する関数を書きます。

# -*- coding: utf-8 -*-

from datetime import datetime as dt

def diff(t1, t2):
	t1 = dt.strptime(t1, '%Y-%m-%dT%H:%M:%S')
	t2 = dt.strptime(t2, '%Y-%m-%dT%H:%M:%S')
	return t1 - t2

次にテストコードを書きます。 二つ目の assert で失敗させるようにします。

# -*- coding: utf-8 -*-

import pytest
import diff as d

def test_diff():
    expected = 365
    actual = d.diff('2014-12-09T00:00:00', '2013-12-09T00:00:00').days
    print('actual: %d, expected: %d' % (actual, expected))
    assert actual == expected

    expected = 12345
    actual = d.diff('2014-12-09T00:00:00', '2013-12-09T00:00:00').seconds
    print('actual: %d, expected: %d' % (actual, expected))
    assert actual == expected

テストを実行します。レポートは簡潔な印象です。

$ pytest test_diff.py
======================================== test session starts ========================================
platform darwin -- Python 2.7.11, pytest-3.8.0, py-1.6.0, pluggy-0.7.1
rootdir: /xxxxx, inifile:
collected 1 item

test_diff.py F                                                                                [100%]

============================================= FAILURES ==============================================
_____________________________________________ test_diff _____________________________________________

    def test_diff():
        expected = 365
        actual = d.diff('2014-12-09T00:00:00', '2013-12-09T00:00:00').days
        print('actual: %d, expected: %d' % (actual, expected))
        assert actual == expected

        expected = 12345
        actual = d.diff('2014-12-09T00:00:00', '2013-12-09T00:00:00').seconds
        print('actual: %d, expected: %d' % (actual, expected))
>       assert actual == expected
E       assert 0 == 12345

test_diff.py:15: AssertionError
--------------------------------------- Captured stdout call ----------------------------------------
actual: 365, expected: 365
actual: 0, expected: 12345
===================================== 1 failed in 0.36 seconds ======================================

pytest.mark.parametrize

続いて pytest.mark.parametrize によるテスト関数の引数のパラメータ化を試してみます。
@parametrize decorator にテスト関数の引数となる複数の tuple を定義します。 tuple の数だけテスト関数が呼ばれます。この機能を使うことでより宣言的なテストになります。

# -*- coding: utf-8 -*-

import pytest
import diff as d

@pytest.mark.parametrize("input,expected", [
    (('2014-12-09T00:00:00', '2014-12-08T00:00:00'), 1),
    (('2014-12-09T00:00:00', '2013-12-09T00:00:00'), 365),
    (('2014-12-09T00:00:00', '2010-12-09T00:00:00'), 365*4+1)
])
def test_diff(input, expected):
    actual = d.diff(input[0], input[1]).days
    print('actual: %d, expected: %d' % (actual, expected))
    assert actual == expected

テストを実行します。

$ pytest test_diff.py
======================================== test session starts ========================================
platform darwin -- Python 2.7.11, pytest-3.8.0, py-1.6.0, pluggy-0.7.1
rootdir: /xxxxx, inifile:
collected 3 items

test_diff.py ...                                                                              [100%]

===================================== 3 passed in 0.10 seconds ======================================

virtualenv をアクティブ化している状態では pytest コマンドは使わず python -m オプションを使いモジュールとして pytest を指定する。

$ python -m pytest test_diff.py
======================================== test session starts ========================================
platform darwin -- Python 2.7.11, pytest-3.8.0, py-1.6.0, pluggy-0.7.1
rootdir: /xxxxx, inifile:
collected 3 items

test_diff.py ...                                                                              [100%]

===================================== 3 passed in 0.18 seconds ======================================