JavaScriptを有効にしてください

pytestを使ってみる②【実行前、実行後処理編】

 ·  ☕ 4 分で読めます · 👀... ページ閲覧数

概要

今回はテスト実行前、実行後(setup, teardown)の処理についてまとめる。

使い方

@pytest.fixture()というデコレータを設定すればよい。
yield以降はテストが実行された後に実行される(teardown)。

使いたいテスト関数の引数にfixtureの関数名を指定すると使うことができる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import pytest


@pytest.fixture
def pre_function():
    print("\n実行前")
    yield "以降は試験実行後に処理される"
    print("\n実行後")


def test_setup_teardown_1(pre_function):
    print("test_1")
    # 試験データ
    a = 1
    b = 1
    assert a == b, "aaa"


def test_setup_teardown_2():
    print("test_2")
    # 試験データ
    a = 2
    b = 2
    assert a == b

実行結果は以下のようになる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 pytest tests/test_setup_teardown.py --capture=no                                                                                                            1 ✘  23:14:41  
======================================================================================== test session starts ========================================================================================
platform darwin -- Python 3.9.0, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
rootdir: /Users/hogehoge/
plugins: html-3.1.1, metadata-1.11.0, cov-2.10.1
collected 2 items                                                                                                                                                                                   

tests/test_setup_teardown.py 
実行前
test_1
.
実行後
test_2
.

========================================================================================= 2 passed in 0.01s =========================================================================================

@pytest.fixtureには色々なオプションを指定することが可能(詳細は公式参照)。
中でもscopeautouseはよく使うと思うので一応まとめてみる。

scope

scope="スコープ名"の形式で設定する(デフォルトはfunction)。fixtureのスコープ(適用範囲)を指定できる。
function, class, module, package, sessionのうちから選ぶ。

スコープ名説明例(以下試してみたで利用した名前)
functionテスト関数の実行前後で setup/teardownが実行される。デフォルト。test_function_1
classテストクラスの実行前後で 〃 。TestClass
moduleテストモジュールの実行前後で 〃 。test_scope_1.py
packageテストパッケージの前後で 〃 。scope/package1
session全体通して一回setup/teardownが実行される。-

autouse

autouse=True or Falseの形式で設定する(デフォルトはFalse)。Trueを設定すると対象のscopeのテストケースを実行するとき自動的にsetup/teardownしてくれる。
試験パターンが多くなってくると個別にfixtureの設定をするのがかなり面倒になるため、共通的なものはautouseを利用すると便利。

試してみた

確認かねて設定したらどんなもんか試してみた。
moduleとpackageの動作確認を行うため以下のような構成にした。

└── tests
    └── scope
         ├── package1 
         |  ├── test_scope_1.py   # function ~ session まで全種類のfixture設定
         |  └── test_scope_2.py   # fixtureの設定なし(module スコープの動作確認用)
         └── package2             
           └── test_package_2.py  # fixtureの設定なし(package スコープの動作確認用)

package1/test_scope_1.py
全種類のfixtureを設定し、自動的に対象のスコープの前後処理が行われるように全てautouseはTrueに設定した。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import pytest


@pytest.fixture(scope="function", autouse=True)
def pre_function():
    scope = "Function"
    print(f"\n=== SETUP {scope} ===")
    yield
    print(f"\n=== TEARDOWN {scope} ===\n")


@pytest.fixture(scope="class", autouse=True)
def pre_class():
    scope = "Class"
    print(f"\n*** SETUP {scope} ***")
    yield
    print(f"\n*** TEARDOWN {scope} ***\n")


@pytest.fixture(scope="module", autouse=True)
def pre_module():
    scope = "Module"
    print(f"\n--- SETUP {scope} ---")
    yield
    print(f"\n--- TEARDOWN {scope} ---\n")


@pytest.fixture(scope="package", autouse=True)
def pre_package():
    scope = "Package"
    print(f"\n<<< SETUP {scope} >>>")
    yield
    print(f"\n<<< TEARDOWN {scope} >>>\n")


@pytest.fixture(scope="session", autouse=True)
def pre_session():
    scope = "Session"
    print(f"\n@@@ SETUP {scope} @@@")
    yield
    print(f"\n@@@ TEARDOWN {scope} @@@\n")


def test_function_1():
    print("test_function_1")
    # 試験データ
    a = 1
    assert a == 1

class TestClass:
    def test_class_1(self):
        print("test_class_1")
        # 試験データ
        a = 1
        assert a == 1

    def test_class_2(self):
        print("test_class_2")
        # 試験データ
        a = 1
        assert a == 1

package1/test_scope_2.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class TestClass:
    def test_class_no_fixture(self):
        print("\ntest_class_no_fixture")
        # 試験データ
        a = 1
        assert a == 1


def test_function_no_fixture():
    print("\ntest_function_no_fixture")
    # 試験データ
    a = 1
    assert a == 1

実行結果は以下の通り。
大体想像通りだったが、メンバ関数ではない普通の関数テストも前後にclass scopeの処理が行われるのが想定外だった。
(python本体のソース見てないが、関数は規定クラスのメンバ関数という位置付けなのかもなと予想。そのうち本体のソース見てみたい。。)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
$  pytest tests/scope --capture=no
======================================================================================== test session starts ========================================================================================
platform darwin -- Python 3.9.0, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
rootdir: /Users/hogehoge
plugins: html-3.1.1, metadata-1.11.0, cov-2.10.1
collected 6 items                                                                                                                                                                                   

tests/scope/package1/test_scope_1.py 
@@@ SETUP Session @@@

<<< SETUP Package >>>

--- SETUP Module ---

*** SETUP Class ***

=== SETUP Function ===
test_function_1
.
=== TEARDOWN Function ===


*** TEARDOWN Class ***


*** SETUP Class ***

=== SETUP Function ===
test_class_1
.
=== TEARDOWN Function ===


=== SETUP Function ===
test_class_2
.
=== TEARDOWN Function ===


*** TEARDOWN Class ***


--- TEARDOWN Module ---


tests/scope/package1/test_scope_2.py 
test_class_no_fixture
.
test_function_no_fixture
.
tests/scope/package2/test_package_2.py 
test_package_2
.
<<< TEARDOWN Package >>>


@@@ TEARDOWN Session @@@

========================================================================================= 6 passed in 0.06s =========================================================================================

感想

testsフォルダ直下には一つ前の記事のpytest用スクリプトがあったのでscope動作確認時のフォルダ構成が気持ち悪い感じになった。記事ごとにフォルダ分ければよかった。
公式をみてみると他にも便利なオプションがたくさんありそうなので、新しいオプション利用する度追記していきたい。

参考

共有

BAMBi
著者
BAMBi
サーバサイド~インフラがメインでフロントも好きです。趣味はアニメ鑑賞、ゲーム、つまみ細工です。