pytestを使用したPythonテスト。 設定、第6章

戻る 次へ







この章では、pytestに影響する構成ファイルを調べ、pytestがそれらに基づいて動作をどのように変更するかを説明し、Tasksプロジェクトの構成タスクにいくつかの変更を加えます。













この本の例は、Python 3.6とpytest 3.2を使用して書かれています。 pytest 3.2は、Python 2.6、2.7、およびPython 3.3+をサポートしています。







Tasksプロジェクトのソースコードと、この本に示されているすべてのテストのソースコードは、 pragprog.comにある本のWebページのリンクから入手できます。 テストコードを理解するためにソースコードをダウンロードする必要はありません。 テストコードは、例では便利な形式で示されています。 ただし、プロジェクトのタスクを実行したり、テストサンプルを調整して自分のプロジェクトをテストしたりするには(手を縛っていない!)、書籍のWebページにアクセスして作品をダウンロードする必要があります。 書籍のWebページには、 正誤表のメッセージへのリンクとディスカッションフォーラムがあります。

ネタバレの下には、このシリーズの記事のリストがあります。









構成



これまでのところ、95ページの第5章「プラグイン」で詳細に説明したconftest.pyを除き、主にpytestに影響を与えるさまざまな非テストファイルについて説明しました。この章では、構成ファイルについて説明します。 pytestに影響を与え、pytestがそれらに基づいて動作をどのように変更するかを議論し、Tasksプロジェクトの構成ファイルにいくつかの変更を加えます。







pytest構成ファイルについて



pytestのデフォルトの動作を変更する方法を説明する前に、pytestのすべての非テストファイル、特に、誰がそれらを処理する必要があるかを調べてみましょう。







次のことを知っておく必要があります。









toxを使用する場合は、次のことに興味があります。









Pythonパッケージ(タスクなど)を配布する場合、このファイルは興味深いものになります。









pytest設定をどのファイルに入れても、フォーマットは基本的に同じです。







pytest.ini









ch6 / format / pytest.ini


 [pytest] addopts = -rsxX -l --tb=short --strict xfail_strict = true ... more options ...
      
      





tox.ini









ch6 / format / tox.ini


 ... tox specific stuff ... [pytest] addopts = -rsxX -l --tb=short --strict xfail_strict = true ... more options ...
      
      





setup.cfg









ch6 / format / setup.cfg


 ... packaging specific stuff ... [tool:pytest] addopts = -rsxX -l --tb=short --strict xfail_strict = true ... more options ...
      
      





唯一の違いは、setup.cfgのセクションヘッダーが[tool:pytest]



ではなく[tool:pytest]



ことです。







pytest -helpを使用して有効なiniファイルオプションを一覧表示する



pytest --help



からpytest --help



のすべての有効なパラメーターのリストを取得できpytest --help









 $ pytest --help ... [pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg file found: markers (linelist) markers for test functions empty_parameter_set_mark (string) default marker for empty parametersets norecursedirs (args) directory patterns to avoid for recursion testpaths (args) directories to search for tests when no files or directories are given in the command line. console_output_style (string) console output: classic or with additional progress information (classic|progress). usefixtures (args) list of default fixtures to be used with this project python_files (args) glob-style file patterns for Python test module discovery python_classes (args) prefixes or glob names for Python test class discovery python_functions (args) prefixes or glob names for Python test function and method discovery xfail_strict (bool) default for the strict parameter of xfail markers when not given explicitly (default: False) junit_suite_name (string) Test suite name for JUnit report junit_logging (string) Write captured log messages to JUnit report: one of no|system-out|system-err doctest_optionflags (args) option flags for doctests doctest_encoding (string) encoding used for doctest files cache_dir (string) cache directory path. filterwarnings (linelist) Each line specifies a pattern for warnings.filterwarnings. Processed after -W and --pythonwarnings. log_print (bool) default value for --no-print-logs log_level (string) default value for --log-level log_format (string) default value for --log-format log_date_format (string) default value for --log-date-format log_cli (bool) enable log display during test run (also known as "live logging"). log_cli_level (string) default value for --log-cli-level log_cli_format (string) default value for --log-cli-format log_cli_date_format (string) default value for --log-cli-date-format log_file (string) default value for --log-file log_file_level (string) default value for --log-file-level log_file_format (string) default value for --log-file-format log_file_date_format (string) default value for --log-file-date-format addopts (args) extra command line options minversion (string) minimally required pytest version xvfb_width (string) Width of the Xvfb display xvfb_height (string) Height of the Xvfb display xvfb_colordepth (string) Color depth of the Xvfb display xvfb_args (args) Additional arguments for Xvfb xvfb_xauth (bool) Generate an Xauthority token for Xvfb. Needs xauth. ...
      
      





この章では、125ページの第7章「他のツールでのpytestの使用」で説明されているdoctest_optionflags



除き、これらの設定をすべて確認できます。







プラグインはiniファイルオプションを追加できます



前の設定リストは一定ではありません。 プラグイン(およびconftest.pyファイル)の場合、iniファイルオプションを追加できます。 追加されたオプションは、pytest --helpコマンドの出力にも追加されます。

ここで、コアpytestで使用可能な.iniファイルの組み込み設定で行うことができるいくつかの構成変更を見てみましょう。







デフォルトのコマンドラインオプションを変更する



pytestのコマンドラインオプションをすでに使用しました。詳細出力-l/--showlocals



-v/--verbose



-verboseは 、失敗したテストのスタックトレースを含むローカル変数を表示します。 them—for a project



は、これらのoptions—or



一部を常に使用するか、使用するthem—for a project



を好むoptions—or



ありoptions—or



。 必要なパラメーターのaddopts



pytest.ini



をインストールする場合、それらを入力する必要はなくなりました。 私が好きなセットは次のとおりです。







 [pytest] addopts = -rsxX -l --tb=short --strict
      
      





-rsxX



使用すると、 xfailed



はすべてのskipped



xfailed



またはxpassed



テストの理由を報告できます。 -l



スイッチを使用すると、pytestは各障害の場合にローカル変数のスタックトレースを表示できます。 --tb=short



は、スタックトレースのほとんどを削除します。 ただし、ファイルと行番号は残ります。 --strict



は、構成ファイルに登録されていないトークンの使用を禁止します。 これを行う方法については、次のセクションで説明します。







マーカーのタイプミスを防ぐためにマーカーを登録する



31ページの「テスト関数のラベル付け」で説明されているカスタムマーカーは、特定のマーカーで実行するテストのサブセットをマークするのに最適です。 ただし、マーカーを間違えるのは簡単すぎるため、最終的にいくつかのテストには@pytest.mark.smoke



というタグが付けられ、一部のテストには@pytest.mark.smoke



というタグが付けられます。 デフォルトでは、これはエラーではありません。 pytestは、2つのマーカーを作成したと考えています。 ただし、これは、次のように、pytest.iniにトークンを登録することで修正できます。







 [pytest] ... markers = smoke: Run the smoke test test functions get: Run the test functions that test tasks.get() ...
      
      





これらのマーカーを登録することにより、 pytest --markers



とその説明を使用して表示することもできます。







 $ cd /path/to/code/ch6/b/tasks_proj/tests $ pytest --markers @pytest.mark.smoke: Run the smoke test test functions @pytest.mark.get: Run the test functions that test tasks.get() @pytest.mark.skip(reason=None): skip the ... ...
      
      





マーカーが登録されていない場合、マーカーは--markers



リストに表示されません。 それらが登録されると、それらはリストに表示されます--strict



を使用すると、エラーのあるトークンまたは未登録のトークンはエラーとして表示されます。 ch6/a/tasks_proj



ch6/b/tasks_proj



の唯一の違いは、pytest.iniファイルの内容です。 ch6/a



空です。 マーカーを登録せずにテストを実行してみましょう。







 $ cd /path/to/code/ch6/a/tasks_proj/tests $ pytest --strict --tb=line ============================= test session starts ============================= collected 45 items / 2 errors =================================== ERRORS ==================================== ______________________ ERROR collecting func/test_add.py ______________________ 'smoke' not a registered marker ________________ ERROR collecting func/test_api_exceptions.py _________________ 'smoke' not a registered marker !!!!!!!!!!!!!!!!!!! Interrupted: 2 errors during collection !!!!!!!!!!!!!!!!!!! =========================== 2 error in 1.10 seconds ===========================
      
      





pytest.ini



マーカーを使用してマーカーを登録する--strict



addopts



--strict



を追加することもできます。 後で感謝します。 先に進み、pytest.iniファイルをタスクプロジェクトに追加しましょう。







pytest.ini



マーカーを使用してマーカーを登録する--strict



は、 addopts



--strict



を追加することもできます。 後で感謝します。 続けて、pytest.iniファイルをタスクプロジェクトに追加します。







pytest.ini



トークンを使用してトークンを登録する場合、 pytest.ini



--strict



して既存のトークンに--strict



を追加することもできます。 クール?! pytest.ini



感謝し、 pytest.ini



ファイルをtasks



プロジェクトに追加します。







ch6 / b / tasks_proj / tests / pytest.ini


 [pytest] addopts = -rsxX -l --tb=short --strict markers = smoke: Run the smoke test test functions get: Run the test functions that test tasks.get()
      
      





デフォルトで優先されるフラグの組み合わせは次のとおりです。









これにより、煙テストなどのテストを実施できます。







 $ cd /path/to/code/ch6/b/tasks_proj/tests $ pytest --strict -m smoke ===================== test session starts ====================== collected 57 items func/test_add.py . func/test_api_exceptions.py .. ===================== 54 tests deselected ====================== =========== 3 passed, 54 deselected in 0.06 seconds ============
      
      





最小のパイテスト要件



minversion



パラメーターを使用minversion



と、テストに必要なpytestの最小バージョンを指定できminversion



。 たとえば、浮動小数点数をテストするときにapprox()



を使用して、テストで「かなり近い」等式を決定するつもりでした。 しかし、この関数はバージョン3.0までpytestに導入されていませんでした。 混乱を避けるために、 approx()



を使用するプロジェクトに以下を追加します。







 [pytest] minversion = 3.0
      
      





したがって、誰かが古いバージョンのpytestを使用してテストを実行しようとすると、エラーメッセージが表示されます。







pytestが間違った場所を検索しないようにする



「再帰」の定義の1つが、独自のコードで2回誓うことであることをご存知ですか? まあ、いや。 実際、これはサブディレクトリのアカウンティングを意味します。 pytestは、再帰的に多数のディレクトリを調べるテスト検出を有効にします。 ただし、pytestの表示から除外するディレクトリがいくつかあります。







norecurse



のデフォルト値は'. * Build dist CVS _darcs {arch} and *.egg. Having '.*'



'. * Build dist CVS _darcs {arch} and *.egg. Having '.*'



'. * Build dist CVS _darcs {arch} and *.egg. Having '.*'



は、ドットで始まるすべてのディレクトリが表示されないため、仮想環境に「.venv」という名前を付ける正当な理由です。







Tasksプロジェクトの場合、pytestを使用してテストファイルを検索するのは時間の無駄になるため、 src



を指定しても害はありません。







 [pytest] norecursedirs = .* venv src *.egg dist build
      
      





このパラメーターなど、既に有用な値を持っているパラメーターをオーバーライドする場合、以前のコードで*.egg dist build



使用して行ったように、デフォルト値が何であるかを知り、必要な値を返すと便利です。

norecursedirs



はテストパスにとっては一種の結果なので、これについては後で見てみましょう。







テストディレクトリツリーの仕様



norecursedirs



はpytestにどこを見るtestpaths



指示しますが、 testpaths



はpytestにどこを見るかを指示します。 testspaths



は、テストを見つけるためのルートディレクトリに相対的なディレクトリのリストです。 ディレクトリ、ファイル、またはnodeid



引数として指定されていない場合にのみ使用されます。







Tasks



プロジェクトの場合、テストの代わりにtasks_proj



ディレクトリに配置するとします。







 \code\tasks_proj>tree/f . │ pytest.ini │ ├───src │ └───tasks │ api.py │ ... │ └───tests │ conftest.py │ pytest.ini │ ├───func │ test_add.py │ ... │ ├───unit │ test_task.py │ __init__.py │ ...
      
      





それから、テストをtestpaths



に入れるのが理にかなっているかもしれません:







 [pytest] testpaths = tests
      
      





これで、 tasks_proj



ディレクトリからpytestを実行すると、pytestはtasks_proj/tests



のみを検索しtasks_proj/tests



。 ここでの問題は、テストの開発およびデバッグ中に、テストディレクトリを繰り返し処理することが多いため、パス全体を指定せずにサブディレクトリまたはファイルを簡単にテストできることです。 したがって、このオプションはインタラクティブなテストで少し役立ちます。







ただし、継続的インテグレーションサーバーまたはトックスから実行するテストには最適です。 これらの場合、ルートディレクトリが修正されることがわかっているため、その修正されたルートディレクトリに関連するディレクトリを一覧表示できます。 これらは、テスト時間を本当に短縮したい場合でもあるので、テストの検索をなくすことは素晴らしいことです。







一見すると、テストパスとnorecursedirs



両方を同時に使用するのはばかげているように思えるかもしれません。 ただし、既に見たように、テストパスはファイルシステムのさまざまな部分からの対話型テストではほとんど役に立ちません。 これらの場合、 norecursedirs



が役立ちます。 さらに、テストを含まないテストディレクトリがある場合は、 norecursedirs



を使用してnorecursedirs



を回避できます。 しかし、実際には、テストを持たないテストに追加のディレクトリを置くことのポイントは何ですか?







テスト検出ルールの変更



pytestは、特定のテスト検出ルールに基づいて実行するテストを見つけます。 標準テスト検出ルール:







•1つ以上のディレクトリから始めます。 コマンドラインでファイルまたはディレクトリの名前を指定できます。 何も指定しなかった場合、現在のディレクトリが使用されます。

•テストモジュールのカタログとそのすべてのサブディレクトリを検索します。

•テストモジュールは、 test_*.py



*_test.py



または*_test.py



類似した名前のファイルです。

•testで始まる関数のテストモジュールを調べます

•Testで始まるクラスを探します。 `test ,



始まる ,



init` ,



クラスのメソッドを探します。







これらは標準の検出ルールです。 ただし、それらは変更できます。







python_classes



pytestとクラスのテストを見つけるための通常のルールは、クラスがTest*



で始まる場合、クラスを潜在的なテストクラスと見なすことです。 クラスに__init__()



メソッドを__init__()



こともできません。 しかし、テストクラスに<something>Test



または<something>Suite



という名前を付けたい場合はどうでしょうか。 python_classes



出番python_classes









 [pytest] python_classes = *Test Test* *Suite
      
      





これにより、次のようなクラスを呼び出すことができます。







 class DeleteSuite(): def test_delete_1(): ... def test_delete_2(): ... ....
      
      





python_files



pytest_classes



と同様に、 python_files



はデフォルトのテスト検出ルールを変更します。これは、 test_*



で始まるファイルまたは最後に*_test



を持つファイルの検索で構成されます。

すべてのテストファイルにcheck_<something>.py



という名前を付けたカスタムテストフレームワークがあるとします。 理にかなっているようです。 すべてのファイルの名前を変更する代わりに、次のようにpytest.ini



行を追加するだけです。







 [pytest] python_files = test_* *_test check_*
      
      





とても簡単です。 必要に応じて、命名規則を徐々に転送するか、単にcheck_*



ままにしておくことがcheck_*









python_functions



python_functions



は以前の2つの設定と同様に機能しますが、テスト関数とメソッド名用です。 デフォルト値はtest_*



です。 そして、 check_*



を追加するにはcheck_*



推測した-これを行う:







 [pytest] python_functions = test_* check_*
      
      





pytest



命名pytest



はそれほど制限されていないようです。 したがって、デフォルトの命名規則が気に入らない場合は、単に変更してください。 それにもかかわらず、私はあなたがそのような決定のためのより説得力のある理由を持っていることをお勧めします。 数百のテストファイルを移行することは、間違いなく正当な理由です。







XPASS禁止



xfail_strict = true



設定すると、 @pytest.mark.xfail



マークされたテストがエラーの原因として認識されないことを意味します。 この設定は常にあるべきだと思います。 xfail



トークンの詳細については、37ページの「失敗を待つテストのマーク付け」を参照してください。







ファイル名の競合を防ぐ



プロジェクトの各テストサブディレクトリに__init__.py



ファイルを__init__.py



ことの有用性は、長い間私を混乱させました。 ただし、それらの有無は簡単です。 すべてのテストサブディレクトリに__init__.py



ファイルがある場合、複数のディレクトリに同じテストファイル名を付けることができます。 そうでない場合、これは機能しません。







以下に例を示します。 ディレクトリa



b



両方にファイルtest_foo.py



があります。 これらのファイルに何が含まれているかは関係ありませんが、この例では次のようになります。







ch6 / dups / a / test_foo.py

 def test_a(): pass
      
      







ch6 / dups / b / test_foo.py

 def test_b(): pass
      
      





このディレクトリ構造では:







 dups ├── a │ └── test_foo.py └── b └── test_foo.py
      
      





これらのファイルには同じ内容さえありませんが、テストは破損しています。 それらを個別に実行することは可能pytest



が、 dups



ディレクトリからpytest



を実行する方法はありません。







 $ cd /path/to/code/ch6/dups $ pytest a ============================= test session starts ============================= collected 1 item a\test_foo.py . ========================== 1 passed in 0.05 seconds =========================== $ pytest b ============================= test session starts ============================= collected 1 item b\test_foo.py . ========================== 1 passed in 0.05 seconds =========================== $ pytest ============================= test session starts ============================= collected 1 item / 1 errors =================================== ERRORS ==================================== _______________________ ERROR collecting b/test_foo.py ________________________ import file mismatch: imported module 'test_foo' has this __file__ attribute: /path/to/code/ch6/dups/a/test_foo.py which is not the same as the test file we want to collect: /path/to/code/ch6/dups/b/test_foo.py HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules !!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!! =========================== 1 error in 0.34 seconds ===========================
      
      





何も明確ではありません!

このエラーメッセージは、問題の原因を示しているわけではありません。







このテストを修正するには、空の__init__.py



ファイルをサブディレクトリに追加するだけです。 同じ重複ファイル名を持つdups_fixed



ディレクトリの例を次に示しますが、 dups_fixed



ファイルが追加されています。







 dups_fixed/ ├── a │ ├── __init__.py │ └── test_foo.py └── b ├── __init__.py └── test_foo.py
      
      





それでは、 dups_fixed



トップレベルからもう一度試してみましょう。







 $ cd /path/to/code/ch6/ch6/dups_fixed/ $ pytest ============================= test session starts ============================= collected 2 items a\test_foo.py . b\test_foo.py . ========================== 2 passed in 0.15 seconds ===========================
      
      





だからそれは良くなります。







もちろん、ファイル名が重複することは決してないと確信できるので、それは問題ではありません。 すべてが正常です。 しかし、プロジェクトは成長しており、テストカタログは成長しています。 これらのファイルをそこに置くだけです。 それを習慣にして、もう一度心配する必要はありません。







演習



95ページの第5章「プラグイン」で、-niceコマンドラインオプションを含むpytest-niceというプラグインを作成しました。 niceと呼ばれるpytest.iniオプションを含めるように拡張しましょう。







95ページの第5章「プラグイン」で、 pytest-nice



コマンドライン--nice



を含むpytest-nice



というプラグインを作成しました。 nice



と呼ばれるpytest.ini



オプションを含めるためにこれを拡張しましょう。







  1. pytest_addoption



    pytest_nice.py



    フック関数に次の行を追加します: parser.addini('nice', type='bool', help='Turn failures into opportunities.')



    pytest_addoption



    pytest_nice.py



    parser.addini('nice', type='bool', help='Turn failures into opportunities.')



  2. getoption()



    を使用するプラグイン内の場所もgetini('nice')



    を呼び出すgetini('nice')



    があります。 これらの変更を行います。
  3. pytest.ini



    ファイルにnice



    を追加して、これを手動で確認します。
  4. プラグインテストを忘れないでください。 テストを追加して、 pytest.ini



    nice



    パラメーターpytest.ini



    正しくpytest.ini



    することを確認します。
  5. プラグインディレクトリにテストを追加します。 追加のPytester機能を見つける必要があります


次は何ですか



pytestはそれ自体が非常に強力ですが(特にプラグインの場合)、他のソフトウェア開発ツールやソフトウェアテストツールともうまく統合できます。 次の章では、他の強力なテストツールと組み合わせたpytestの使用について検討します。







戻る 次へ








All Articles