Skip to content

Instantly share code, notes, and snippets.

@aodag
Forked from shiumachi/pytest.md
Last active March 2, 2020 14:00
Show Gist options
  • Save aodag/08d63828bb582fdb7599014d637cb863 to your computer and use it in GitHub Desktop.
Save aodag/08d63828bb582fdb7599014d637cb863 to your computer and use it in GitHub Desktop.
Pytestの書き方入門

インストール

pip install pytest pytest-cov pytest-randomly pytest-mock
  • pytest-cov: カバレッジ計測プラグイン
  • pytest-randomly: 実行順のランダム化
  • pytest-mock: mock利用プラグイン

書き方

import pytest

class TestClassA:

  @pytest.fixture
  def target(self):
    """ setUp / tearDown の代わりに fixture を使う。テストの前に呼び出される
    """
    from name.space.to.moduleX import ClassA
    return ClassA
    
  @pytest.mark.parametrize("x, expected", # テストのパラメータ化はここで行う
    [
        (1, 2), 
        (2, 3)
    ]
  def test_f(self, target, mocker, x, expected):
    mock_ClassB = mocker.patch("name.space.to.moduleX.ClassB") # mockしておけば呼び出し先の実装は気にしなくていい
    obj = target()
    result = obj.f(x)
    
    assert result == expected
    mock_ClassB.assert_called_with(x) # mockを使ったら必ず渡している引数のテストを書く
    

実行

pytest

オプション

最後に失敗したものだけ実行

pytest --lf

カバレッジ表示

html出力

pytest --cov-report=html

テストを書いてない行を表示

pytest --cov-report=term-missing

Tips

mocker.patchはどこにパッチするか

個人的に一番ハマった場所。 テスト対象のモジュールから見たときの名前空間をパッチするのだが、説明するよりも実例を見る方が早い。

/name/space/to/moduleX.py に書いてある ClassA をテストしたいとする。 このモジュールでは /name/space/to/moduleY.py に書いてある ClassB を以下のようにimportしている。

from name.space.to.moduleY import ClassB

このときパッチを当てる名前空間は name.space.to.moduleX.ClassB である。 moduleY でないことに注意。

テストディレクトリの切り方

基本は tests/test_<name>/test_<space>/test_<to>/test_moduleX.py と書くのだが、私は以下のような書き方をしている。

tests/
  system/
    name/
      space/
          to/
            test_moduleX.py
  unit/
    name/
      space/
          to/
            test_moduleX.py

外部接続を行わないユニットテストを unit 以下に、外部接続(他システムAPIを叩くなど)を必要とするテストを system 以下に書くようにしている。 もちろん単体で完結するパッケージならこのようにする必要はない。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment