LoginSignup
1
4

More than 3 years have passed since last update.

pytest使い方まとめ

Posted at

今まで「テストコード」をほとんど書いたことがなかったのですが、pythonのテストコードを書く機会があり、慌てて使い方を学びました。本記事ではpython単体テストのフレームワークであるpytestの使い方を要点を絞ってまとめました。

参考:公式ドキュメント(https://docs.pytest.org/en/latest/contents.html)


pytestとは

pythonでの単体テストを行うためのフレームワーク。同様なものでunittestというものがあるが、pytestの方が人気らしい。
下記がpytestの特徴

  • テスト失敗時の情報が詳細
  • テスト対象のモジュール、関数を自動で発見
  • フィクスチャ機能を利用することで、モックなど、テストの前処理ができる。(後述)
  • unittestにも準拠している

インストール

pip install -U pytest

簡単な使用方法

単純な単体テスト

基本的に、下記の要領でテストを実行できる。

  • テストケースをassert <条件式> で記載する
  • pytestを実行する

ファイル名, メソッド名をtest_*で記載すると、自動でテストコードを発見してくれる(自分で指定することも可能)

test_sample.py
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により、例外のテストが可能

error_sample.py
import pytest

def f():
    raise SystemExit(1)

def test_mytest():
    with pytest.raises(SystemExit):
        f()

クラス内の複数のテストの実行

Testをprefixとしたクラスを作成することで、内部のテストメソッドを同時にテストできる。

test_class.py
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フィクスチャにより、テスト時に一時的に利用できる固有のディレクトリを作成できる。

test_tempdir.py
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()が容易に実行できない関数だとする。

monkeypatch_product.py
def return_value(): # プロダクトコード
    a = get_value()
    return a

def get_value(): # 容易に実行できない関数
    return 1

この時、monkeypatch.setattrによりget_value()を自作のモック関数に差し替えてテストを実行することができる。

monkeypatch_test.py
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で環境変数のモック化も可能。

monkeypatch_env.py
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"
1
4
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
1
4