今まで**「テストコード」**をほとんど書いたことがなかったのですが、pythonのテストコードを書く機会があり、慌てて使い方を学びました。本記事ではpython単体テストのフレームワークであるpytestの使い方を要点を絞ってまとめました。
参考:公式ドキュメント(https://docs.pytest.org/en/latest/contents.html)
pytestとは
pythonでの単体テストを行うためのフレームワーク。同様なものでunittestというものがあるが、pytestの方が人気らしい。
下記がpytestの特徴
- テスト失敗時の情報が詳細
- テスト対象のモジュール、関数を自動で発見
- フィクスチャ機能を利用することで、モックなど、テストの前処理ができる。(後述)
- unittestにも準拠している
インストール
pip install -U pytest
簡単な使用方法
単純な単体テスト
基本的に、下記の要領でテストを実行できる。
- テストケースを
assert <条件式>
で記載する -
pytest
を実行する
ファイル名, メソッド名をtest_*
で記載すると、自動でテストコードを発見してくれる(自分で指定することも可能)
def func(x):
return x + 1
def test_answer():
assert func(3) == 5
上記test_sample.pyファイルを作成し、
pytest
を実行。
すると、下記のようなテスト結果が表示される。
テスト結果
========================================== test session starts ===========================================
platform darwin -- Python 3.7.6, pytest-5.4.3, py-1.8.1, pluggy-0.13.1
rootdir: /Users/xin/work/study/pytest
plugins: hypothesis-5.5.4, arraydiff-0.3, remotedata-0.3.2, openfiles-0.4.0, doctestplus-0.5.0, astropy-header-0.1.2
collected 1 item
test_sample.py F [100%]
================================================ FAILURES ================================================
______________________________________________ test_answer _______________________________________________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:5: AssertionError
======================================== short test summary info =========================================
FAILED test_sample.py::test_answer - assert 4 == 5
=========================================== 1 failed in 0.18s ============================================
例外処理のテスト
pytest.raises
により、例外のテストが可能
import pytest
def f():
raise SystemExit(1)
def test_mytest():
with pytest.raises(SystemExit):
f()
クラス内の複数のテストの実行
Test
をprefixとしたクラスを作成することで、内部のテストメソッドを同時にテストできる。
class TestClass:
def test_one(self):
x = "this"
assert "h" in x
def test_two(self):
x = "hello"
assert hasattr(x, "check")
フィクスチャ
フィクスチャとは
テストの実行環境をセットアップするために用意されたツール。
いくつか便利そうなものをピックアップします。
詳細は下記を参照(https://docs.pytest.org/en/latest/fixture.html)
tmpdir
tmpdir
フィクスチャにより、テスト時に一時的に利用できる固有のディレクトリを作成できる。
import os
def test_create_file(tmpdir):
p = tmpdir.mkdir("sub").join("hello.txt") # 一時ディレクトリの作成
p.write("content")
assert p.read() == "content"
assert len(tmpdir.listdir()) == 1
assert 0
monkeypatch
monkeypatch
フィクスチャにより、オブジェクトのモックを作成できる。
例えば下記のようなプロダクトコードがあり、仮に一get_value()
が容易に実行できない関数だとする。
def return_value(): # プロダクトコード
a = get_value()
return a
def get_value(): # 容易に実行できない関数
return 1
この時、monkeypatch.setattr
によりget_value()
を自作のモック関数に差し替えてテストを実行することができる。
import monkeypatch_product
# テストコード
def test_return_value(monkeypatch):
def mock_get_value():
return 100
# モック関数に差し替え
monkeypatch.setattr(monkeypatch_product, "get_value", mock_get_value)
res = monkeypatch_product.return_value()
assert res == 100
また、monkeypatch.setenv
で環境変数のモック化も可能。
import os
# プロダクトコード
def get_os_user_lower():
username = os.getenv("USER")
if username is None:
raise OSError("USER environment is not set.")
return username.lower()
# テストコード
def test_get_os_user_lower(monkeypatch):
monkeypatch.setenv("USER", "TestingUser")
assert get_os_user_lower() == "testinguser"