演習

完了

この演習では、pytestparametrize を使用して関数をテストします。 次に、テスト クラスを更新して、setup() メソッドと teardown() メソッドの代わりにフィクスチャを使用します。 parametrize を使用してフィクスチャを操作すると、テストを作成または更新するときに柔軟性を高めることができます。

ステップ 1 - この演習用のテスト ファイルを追加する

  1. test_advanced.py という新しいテスト ファイルを作成し、以下のコードを追加します。

    def str_to_bool(string):
        if string.lower() in ['yes', 'y', '1']:
            return True
        elif string.lower() in ['no', 'n', '0']:
            return False
    
    

    関数 str_to_bool() は入力として文字列を受け取り、内容に応じて True または False の値を返します。

  2. 同じファイルに、関数 str_to_bool() 用のテストを追加します。 最初にすべての true 値をテストするために pytest.mark.parametrize() を使用します。

    import pytest 
    
    @pytest.mark.parametrize("string", ['Y', 'y', '1', 'YES'])
    def test_str_to_bool_true(string):
        assert str_to_bool(string) is True
    
  3. 次に、false 値を使用した別のテストを追加します。

    @pytest.mark.parametrize("string", ['N', 'n', '0', 'NO'])
    def test_str_to_bool_false(string):
        assert str_to_bool(string) is False
    

    TrueFalse の両方の戻り値に対して可能なすべての入力をカバーするテストが 2 つあります。

実際のコードと同じファイル内にテストを含めるのは一般的ではありません。 わかりやすくするために、この演習の例では、同じファイルに実際のコードが含まれています。 実際の Python プロジェクトでは、テストしているコードから、ファイルとディレクトリによってテストが分離されています。

ステップ 2 - テストを実行し、レポートを探索する

テストを追加した後、次のステップでは、pytest を実行して出力を検査します。 詳細度の増加フラグ (-v) を使用して、すべての入力値が個別のテストとして扱われているのを確認できるようにします。

$ pytest -v test_avanced.py
============================= test session starts ==============================
Python 3.9.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 
rootdir: /private
collected 8 items

test_advanced.py::test_str_to_bool_true[Y] PASSED                        [ 12%]
test_advanced.py::test_str_to_bool_true[y] PASSED                        [ 25%]
test_advanced.py::test_str_to_bool_true[1] PASSED                        [ 37%]
test_advanced.py::test_str_to_bool_true[YES] PASSED                      [ 50%]
test_advanced.py::test_str_to_bool_false[N] PASSED                       [ 62%]
test_advanced.py::test_str_to_bool_false[n] PASSED                       [ 75%]
test_advanced.py::test_str_to_bool_false[0] PASSED                       [ 87%]
test_advanced.py::test_str_to_bool_false[NO] PASSED                      [100%]

============================== 8 passed in 0.01s ===============================

記述したテスト関数は 2 つだけですが、pytest では関数 parametrize() のおかげで合計で 8 つのテストを作成できました。

ステップ 3 - 既存のテストをフィクスチャに移植する

  1. test_advanced.py ファイルに新しいクラス ベースのテストを追加します。 このテストでは、テキストを含む一時ファイルを作成する関数 setup()teardown() を使用する必要があります。 各テストの後、ファイルは削除されます。 次のようになります。

    import os
    
    
    class TestFile:
    
        def setup(self):
            with open("/tmp/done", 'w') as _f:
                _f.write("1")
    
        def teardown(self):
            try:
                os.remove("/tmp/done")
            except OSError:
                pass
    
        def test_done_file(self):
            with open("/tmp/done") as _f:
                contents = _f.read()
            assert contents == "1"
    

    このテスト クラスはファイルを作成しますが、/tmp/ パスがすべてのシステムに存在すると保証されるわけではないので、問題があります。

  2. 以下のように pytesttmpdir() フィクスチャを使用してファイルに書き込みを行いパスを返すフィクスチャを作成します。

    import pytest
    
    @pytest.fixture
    def tmpfile(tmpdir):
        def write():
            file = tmpdir.join("done")
            file.write("1")
            return file.strpath
        return write
    

    tmpfile() フィクスチャでは Pytest の tmpdir() フィクスチャを使用します。これにより、テストの完了後に消去される有効な一時ファイルが保証されます。

  3. ヘルパー メソッドの "TestFile" フィクスチャを使用するように クラスを更新します。

    class TestFile:
    
        def test_f(self, tmpfile):
            path = tmpfile()
            with open(path) as _f:
                contents = _f.read()
            assert contents == "1"
    

    このテスト クラスでは、一時ファイルが作成され、アサーションが機能するための適切な内容が含まれていることを確認できるようになりました。

作業を確認

これで、次のコードを含む test_advanced.py という名前の Python ファイルが作成されます。

  • 文字列を受け取り、文字列の内容に応じてブール値を返す関数 str_to_bool()
  • 関数 str_to_bool() のパラメーター化された 2 つのテスト。1 つは True 値をテストし、もう 1 つは False 値をテストします。
  • pytest フィクスチャを使用して、いくつかの内容を含む一時 tmpdir() ファイルを作成するカスタム フィクスチャ。
  • カスタム tmpfile() フィクスチャを使用してファイルを作成するテスト クラス。

すべてのテストが、ターミナルで実行したときにエラーなしで成功する必要があります。