Skip to content

Instantly share code, notes, and snippets.

@oyakata
Created February 16, 2012 07:17
Show Gist options
  • Save oyakata/1842905 to your computer and use it in GitHub Desktop.
Save oyakata/1842905 to your computer and use it in GitHub Desktop.
pytestをちょっと試した

pytest

Installation and execution

$ pip install pytest

$ py.test test_foo.py

カスタムマーカーの定義

py.testコマンドを実行するとpytest.iniがあると自動的に読み込まれる。 ここにカスタムマーカーを定義しておける。

定義済みマーカーを確認するにはpy.testに --markers オプションを付ける。:

(py27)oyakata@ubuntu:~/Documents/ptst$ py.test --markers
@pytest.mark.heavy: Very slow, heavy test.

@pytest.mark.with_http: Tests uses http connection.

(以下略)

Parametrizing tests

pytest.mark.parametrizeデコレータを使ってテストの内容と条件を分けて書ける。 サンプルコードにもあるが、簡単な例を示すと以下の通り。

例:

import pytest


def foo(a, b):
    return a + b


@pytest.mark.parametrize(("num1", "num2", "expect"), [
    (1, 2, 3),
    (3, 4, 7),
])
def test_foo(num1, num2, expect):
    assert foo(num1, num2) == expect

Funcargs

pytestにはfuncargsという仕組みがある。

funcargsとはテストメソッドの引数のファクトリで、 py.testコマンドのオプションを独自に定義してその値に応じてテスト条件を変えたりテストをスキップできる。

また、py.testのビルトインfuncargsもいくつかあって、 例えばtmpdirという名前の引数は自動的にpy.path.localのオブジェクトに置き換わる。

考え方やアプローチとしては良さそうなのだが、unittestと共存できない点に注意。 (unittest.TestCaseのメソッドはself一つだけを引数に取るので、 funcargsを注入しようとするとエラーになってしまう。)

#-*- coding: utf-8 -*-
def hamburger(becon, lettuce, tomato):
return becon + lettuce + tomato
def veggie_burger(becon, lettuce, tomato):
if becon > 1:
return -1
return becon * (lettuce + tomato)
def whopper(power):
return hamburger(1, 2, 3) * power
[pytest]
markers =
heavy: Very slow, heavy test.
with_http: Tests uses http connection.
#-*- coding: utf-8 -*-
import pytest
import unittest
import hamburger
def pytest_funcarg__tomato(request):
return 7
def test_salad(tomato):
assert hamburger.hamburger(20, 5, tomato) == 32
@pytest.mark.parametrize(("tomato", "bacon", "lettuce", "expect"), [
# テスト関数の引数と順番が違っていても名前で判別するのでOKになる。
# また、parametrizeとfuncargが競合したときはparametrizeが優先される。
# つまり、このテスト関数を実行しても引数tomatoが強制的に7にされることはない。
(1, 2, 3, -1),
(2, 1, 3, 5),
(2, 0, 3, 0),
])
def test_veggie_burger(bacon, lettuce, tomato, expect):
assert hamburger.veggie_burger(bacon, lettuce, tomato) == expect
def test_salad2(tomato):
# parametrizeが付いていないので引数tomatoには7が渡される。
assert hamburger.veggie_burger(tomato, 10, 10) != 140
class HamburgerTest(unittest.TestCase):
def test(self):
"""Test light menu."""
self.assertEqual(hamburger.hamburger(1, 2, 3), 6)
@pytest.mark.heavy
class WhopperTest(unittest.TestCase):
"""heavyマークが付いているので py.test -m "not heavy"とすると対象外になる。
マークにnotを付けられるところが良い。
:!py.test -m "not heavy"
=== test session starts ===
platform linux2 -- Python 2.7.1 -- pytest-2.2.3
collected 8 items
test_hamburger.py ......
=== 2 tests deselected by "-m 'not heavy'" ===
=== 6 passed, 2 deselected in 0.03 seconds ===
なお、-mオプションを複数渡した場合は最後に渡したものが利用される。
この例では -m "heavy" -m "not heavy" -m "None" だったら
Noneマーカーのついたテストはないので何も実行されない。
更に、 -m "foo and not bar" というように、複数のマーカーを使った式を渡せる。
"""
def test_double_whopper(self):
"""Test double whopper."""
self.assertEqual(hamburger.whopper(2), 6 * 2)
def test_triple_whopper(self):
"""Test trible whopper."""
self.assertEqual(hamburger.whopper(3), 6 * 3)
if __name__ == "__main__":
# unittest.mainから実行した場合は
# py.test専用のテストケースは無視されて3件のテストが実行される。
# py.test提供のデコレータが付いていても邪魔はしない。
# :!python test_hamburger.py
# ...
# ----------------------------------------------------------------------
# Ran 3 tests in 0.000s
#
# OK
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment