pytestで堅牢なテストを組み立てましょう。フィクスチャの注入、yieldによる後片付け、表形式のパラメーター化、そして広いスコープの落とし穴です。
このレッスンを Kodokon で開くpytestは二つの強い発想の上に成り立っています。規約による発見(test_*.pyというファイル、test_*という関数)と、素のassertです。assertのイントロスペクションは、失敗したときに両辺の実際の値を表示してくれます - もうassertEqualとその三十もの派生形を覚える必要はありません。すぐに知っておくべき道具が二つあります。例外が確かに送出されることを確かめるpytest.raisesと、二進の丸めと戦わずに浮動小数点数を比較するpytest.approxです。
import pytest
def divide(a: float, b: float) -> float:
return a / b
def test_nominal() -> None:
assert divide(8, 4) == 2.0
def test_zero_division() -> None:
with pytest.raises(ZeroDivisionError):
divide(1, 0)
def test_floats() -> None:
assert 0.1 + 0.2 == pytest.approx(0.3)フィクスチャはpytestの依存性注入です。フィクスチャの名前を持つパラメーターを宣言すれば、pytestがそれを組み立てて注入してくれます。yieldは準備と後片付けを分けます - そのあとのコードはテストが失敗しても実行されます。scopeパラメーター(デフォルトはfunction、ほかにmodule、session)はオブジェクトの寿命を制御します。共有するフィクスチャはconftest.pyに置きましょう。インポートを一つも書かずに、フォルダー全体で使えるようになります。
import sqlite3
import pytest
@pytest.fixture
def db():
conn = sqlite3.connect(":memory:")
conn.execute("CREATE TABLE users (name TEXT)")
yield conn
conn.close()
def test_insert(db) -> None:
db.execute("INSERT INTO users VALUES ('Ada')")
query = "SELECT name FROM users"
rows = db.execute(query).fetchall()
assert rows == [("Ada",)]@pytest.mark.parametrizeはテストをケースの表に変えます。各タプルが独立したテストになり、個別に名前が付いて絞り込めます。parametrizeデコレーターを重ねれば、パラメーターの直積が得られます。pytest.param(..., id='...')でケースに読みやすいidを付けましょう - 失敗のレポートは、ソースファイルを開かなくても理解できるべきです。
import pytest
def slugify(text: str) -> str:
return "-".join(text.lower().split())
@pytest.mark.parametrize(
("raw", "expected"),
[
("Hello World", "hello-world"),
(" Python rocks ", "python-rocks"),
pytest.param("", "", id="empty"),
],
)
def test_slugify(raw: str, expected: str) -> None:
assert slugify(raw) == expectedpytest -x --lf
pytest -k "slugify and not empty"
pytest -q --durations=5yieldのあとに置かれたコードは何のためのものですか?pytest --lfというコマンドは何をしますか?