pytestに付属している組み込みのフィクスチャを使用すると、テストで非常に便利なことを簡単かつ自然に行うことができます。 たとえば、一時ファイルの処理に加えて、pytestには、コマンドラインパラメーターへのアクセス、テストセッション間の通信、出力ストリームの確認、環境変数の変更、アラートのポーリングのための組み込みフィクスチャが含まれています。

Tasksプロジェクトのソースコードと、この本に示されているすべてのテストのソースコードは、 pragprog.comにある本のWebページのリンクから入手できます。 テストコードを理解するためにソースコードをダウンロードする必要はありません。 テストコードは、例では便利な形式で示されています。 ただし、プロジェクトのタスクを実行したり、テストサンプルを調整して自分のプロジェクトをチェックしたりするには(手を縛っていない!)、書籍のWebページにアクセスして作品をダウンロードする必要があります。 書籍のウェブページには、 正誤表の投稿とディスカッションフォーラムへのリンクがあります。
ネタバレの下には、このシリーズの記事のリストがあります。
前の章では、フィクスチャとは何か、フィクスチャの書き方、テストデータとセットアップおよび分解コードのためにそれらを使用する方法について見てきました。
また、conftest.pyを使用して、複数のテストファイルのテスト間でフィクスチャを共有しました。 第3章の終わりに、Tasksプロジェクトの49ページのpytest Fixturesに次のフィクスチャがインストールされました。それらが必要です。
通常のフィクスチャを再利用することは、pytestの開発者が一般的に必要とするフィクスチャをpytestに含めたという良いアイデアです。 59ページのTasksプロジェクトのフィクスチャのスコープ変更セクションで、Tasksプロジェクトがtmpdirとtmpdir_factoryをどのように使用するかを既に見てきました。これらについては、この章で詳しく説明します。
pytestに付属している組み込みのフィクスチャは、テストで非常に便利なことを簡単かつ自然に行うのに役立ちます。 たとえば、一時ファイルの処理に加えて、pytestには、コマンドラインパラメーターへのアクセス、テストセッション間の通信、出力ストリームのチェック、環境変数の変更、およびアラートのポーリングのための組み込みフィクスチャが含まれています。 組み込みのフィクスチャは、pytestコア機能の拡張機能です。 次に、最も一般的に使用されるいくつかのインラインフィクスチャを順番に見てみましょう。
tmpdirおよびtmpdir_factoryの使用
 ファイルの読み取り、書き込み、または変更を行うものをテストする場合は、tmpdirを使用して単一のテストで使用されるファイルまたはディレクトリを作成できます。また、複数のテスト用にディレクトリを設定する場合はtmpdir_factory
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    を使用できます。 
  tmpdir tmpdir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    には関数スコープがあり、 tmpdir_factory
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    フィクスチャにはセッションスコープがあります。  1つのテストだけに一時ディレクトリまたはファイルを必要とする単一のテストでは、 tmpdir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    を使用できます。 これはフィクスチャにも当てはまります。フィクスチャは、テスト機能ごとに再作成する必要があるディレクトリまたはファイルをカスタマイズします。 
  tmpdir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    を使用した簡単な例を次に示しtmpdir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     。 
ch4/test_tmpdir.py
 def test_tmpdir(tmpdir): # tmpdir    ,    # join()  ,    , #     a_file = tmpdir.join('something.txt') #    a_sub_dir = tmpdir.mkdir('anything') #      (  ) another_file = a_sub_dir.join('something_else.txt') #    'something.txt' a_file.write('contents may settle during shipping') #    'anything/something_else.txt' another_file.write('something different') #      assert a_file.read() == 'contents may settle during shipping' assert another_file.read() == 'something different'
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
        tmpdir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    から返される値は、タイプpy.path.local.1
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    オブジェクトです。これは、一時ディレクトリとファイルに必要なもののすべてです。 ただし、1つのトリックがあります。  tmpdir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    フィクスチャtmpdir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     関数スコープとして定義されているため、 tmpdir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    使用して、複数のテスト関数で使用できるフォルダーまたはファイルを作成することはできません。 関数(クラス、モジュール、セッション)以外のスコープを持つフィクスチャの場合、 tmpdir_factory
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    が利用可能です。 
  tmpdir_factory tmpdir_factory
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     tmpdir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    に非常に似ていますが、異なるインターフェースを持っています。  「スコープフィクスチャの仕様」セクション(56ページ)で説明されているように、関数エリアフィクスチャは各テスト関数に対して1回実行され、モジュールエリアフィクスチャはモジュールごとに1回実行され、クラスフィクスチャはクラスごとに1回実行され、エリア検証テストセッションごとに1回動作します。 したがって、セッション領域レコードで作成されたリソースには、セッション全体の有効期間があります。  tmpdir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    とtmpdir_factory
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    類似性を示すために、 tmpdir_factory
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     tmpdir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    例をtmpdir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     。 
ch4 / test_tmpdir.py
 def test_tmpdir_factory(tmpdir_factory): #      . a_dir   # ,    tmpdir a_dir = tmpdir_factory.mktemp('mydir') # base_temp    'mydir'    #  getbasetemp(),  # ,    base_temp = tmpdir_factory.getbasetemp() print('base:', base_temp) #       , #    ' test_tmpdir ()',   , #    a_dir  tmpdir a_file = a_dir.join('something.txt') a_sub_dir = a_dir.mkdir('anything') another_file = a_sub_dir.join('something_else.txt') a_file.write('contents may settle during shipping') another_file.write('something different') assert a_file.read() == 'contents may settle during shipping' assert another_file.read() == 'something different'
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
       最初の行はmktemp('mydir')
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    を使用してディレクトリを作成し、 a_dir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ます。 関数の残りの部分では、 tmpdir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    から返されるtmpdir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    と同じ方法でa_dir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    を使用できます。 
  tmpdir_factory
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    例の2行目では、 getbasetemp()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    関数はこのセッションに使用されるベースディレクトリを返します。 この例のprintステートメントは、システム上のディレクトリを表示できるようにするために必要です。 それがどこにあるか見てみましょう: 
 $ cd /path/to/code/ch4 $ pytest -q -s test_tmpdir.py::test_tmpdir_factory base: /private/var/folders/53/zv4j_zc506x2xq25l31qxvxm0000gn/T/pytest-of-okken/pytest-732 . 1 passed in 0.04 seconds
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
       このベースディレクトリはシステムとユーザーに依存し、 pytest - NUM
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    が増加するたびにpytest - NUM
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    がセッションごとに変化します。 ベースディレクトリは、セッション後にそのまま残されます。  pytestはそれをクリーンアップし、最後の数個の一時ベースディレクトリのみがシステムに残ります。これは、テスト実行後にファイルをチェックするのが待ち遠しい場合は問題ありません。 
  pytest --basetemp=mydir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    を使用する必要がある場合は、独自のベースディレクトリを指定することもできます。 
他の領域に一時ディレクトリを使用する
  tmpdir_factory
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    から一時ディレクトリとセッション領域ファイルを取得し、 tmpdir
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    から関数ディレクトリと領域ファイルを取得します。 しかし、他の領域はどうですか? モジュールまたはクラスのスコープの一時ディレクトリが必要な場合はどうなりますか? これを行うには、目的のサイズの領域の別のフィクスチャを作成します。これにはtmpdir_factory
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    を使用する必要があります。 
たとえば、テストでいっぱいのモジュールがあり、それらの多くがjsonファイルからいくつかのデータを読み取ることができると仮定します。 フィクスチャボリュームフィクスチャをモジュール自体またはconftest.pyファイルに配置することができました。これにより、データファイルが次のように設定されます。
ch4 / authors / conftest.py
 """Demonstrate tmpdir_factory.""" import json import pytest @pytest.fixture(scope='module') def author_file_json(tmpdir_factory): """     .""" python_author_data = { 'Ned': {'City': 'Boston'}, 'Brian': {'City': 'Portland'}, 'Luciano': {'City': 'Sau Paulo'} } file = tmpdir_factory.mktemp('data').join('author_file.json') print('file:{}'.format(str(file))) with file.open('w') as f: json.dump(python_author_data, f) return file
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
       フィクスチャauthor_file_json()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    は、 dataという一時ディレクトリを作成し、データディレクトリにauthor_file.jsonというファイルを作成します。 次に、 python_author_data
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    辞書をjsonとして書き込みます。 これはフィクスチャエリアモジュールであるため、テストを使用してモジュールごとにjsonファイルが1回だけ作成されます。 
ch4 / authors / test_authors.py
 """ ,    .""" import json def test_brian_in_portland(author_file_json): """,   .""" with author_file_json.open() as f: authors = json.load(f) assert authors['Brian']['City'] == 'Portland' def test_all_have_cities(author_file_json): """        .""" with author_file_json.open() as f: authors = json.load(f) for a in authors: assert len(authors[a]['City']) > 0
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      両方のテストで同じJSONファイルが使用されます。 1つのテストデータファイルが複数のテストで機能する場合、両方のテストで再作成しても意味がありません。
pytestconfigを使用する
pytestconfigビルトインフィクスチャを使用すると、pytestが引数とコマンドラインオプション、構成ファイル、プラグイン、およびpytestを起動したディレクトリでどのように動作するかを制御できます。 pytestconfigフィクスチャはrequest.configのショートカットであり、pytestのドキュメントでは「 pytest configオブジェクト 」(pytest構成オブジェクト)と呼ばれることもあります。
pytestconfigの仕組みを調べるには、カスタムコマンドラインパラメーターを追加し、テストからパラメーター値を読み取る方法を確認できます。 pytestconfigからコマンドラインパラメーターの値を直接読み取ることができますが、パラメーターを追加して分析するには、フック関数を追加する必要があります。 95ページの第5章「プラグイン」で詳しく説明するフック関数は、pytestの動作を制御する別の方法であり、プラグインでよく使用されます。 ただし、カスタムコマンドラインオプションを追加してpytestconfigから読み取ることは非常に一般的であるため、ここで説明します。
  pytestフック pytest_addoption
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    を使用して、pytestコマンドラインで既に利用可能なパラメーターにいくつかのパラメーターを追加します。 
ch4 / pytestconfig / conftest.py
 def pytest_addoption(parser): parser.addoption("--myopt", action="store_true", help="some boolean option") parser.addoption("--foo", action="store", default="bar", help="foo: bar or baz")
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
        pytest_addoption
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    を使用してコマンドラインパラメーターを追加するには、プラグインを使用するか、プロジェクトディレクトリ構造の最上部にあるconftest.pyファイルを使用します。  testサブディレクトリでこれを行うべきではありません。 
  --myopt
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    および--foo <value>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    オプションが前のコードに追加され、ヘルプ行が次のように変更されました。 
 $ cd /path/to/code/ch4/pytestconfig $ pytest --help usage: pytest [options] [file_or_dir] [file_or_dir] [...] ... custom options: --myopt some boolean option --foo=FOO foo: bar or baz ...
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      これで、テストからこれらのオプションにアクセスできます。
ch4 / pytestconfig / test_config.py
 import pytest def test_option(pytestconfig): print('"foo" set to:', pytestconfig.getoption('foo')) print('"myopt" set to:', pytestconfig.getoption('myopt'))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      仕組みを見てみましょう。
 $ pytest -s -q test_config.py::test_option "foo" set to: bar "myopt" set to: False .1 passed in 0.01 seconds $ pytest -s -q --myopt test_config.py::test_option "foo" set to: bar "myopt" set to: True .1 passed in 0.01 seconds $ pytest -s -q --myopt --foo baz test_config.py::test_option "foo" set to: baz "myopt" set to: True .1 passed in 0.01 seconds
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      pytestconfigはフィクスチャであるため、他のフィクスチャからも取得できます。 必要に応じて、オプション名のフィクスチャを作成できます。例:
ch4 / pytestconfig / test_config.py
 @pytest.fixture() def foo(pytestconfig): return pytestconfig.option.foo @pytest.fixture() def myopt(pytestconfig): return pytestconfig.option.myopt def test_fixtures_for_options(foo, myopt): print('"foo" set to:', foo) print('"myopt" set to:', myopt)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      また、追加されたパラメーターだけでなく、組み込みパラメーターにアクセスしたり、pytestの起動方法に関する情報(ディレクトリ、引数など)にアクセスしたりすることもできます。
次に、いくつかの値と構成オプションの例を示します。
 def test_pytestconfig(pytestconfig): print('args :', pytestconfig.args) print('inifile :', pytestconfig.inifile) print('invocation_dir :', pytestconfig.invocation_dir) print('rootdir :', pytestconfig.rootdir) print('-k EXPRESSION :', pytestconfig.getoption('keyword')) print('-v, --verbose :', pytestconfig.getoption('verbose')) print('-q, --quiet :', pytestconfig.getoption('quiet')) print('-l, --showlocals:', pytestconfig.getoption('showlocals')) print('--tb=style :', pytestconfig.getoption('tbstyle'))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      113ページの第6章「構成」でiniファイルをデモンストレーションするときに、pytestconfigに戻ります。
キャッシュを使用する
通常、テスターは、各テストが他のテストから可能な限り独立していると考えています。 注文会計の依存関係が入り込まないことを確認する必要があります。 任意のテストを任意の順序で実行または再起動して、同じ結果が得られるようにしたいと思います。 さらに、テストセッションは繰り返し可能で、以前のテストセッションに基づいて動作を変更しない必要があります。
 ただし、あるテストセッションから別のテストセッションに情報を転送することが非常に役立つ場合があります。 将来のテストセッションに情報を渡したい場合は、組み込みのcache
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    フィクスチャを使用してこれを行うことができます。 
 フィクスチャcache
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     、1つのテストセッションに関する情報を保存し、次のセッションで取得するように設計されています。 このケースの利益のためにcache
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    パーミッションを使用する素晴らしい例は、組み込み機能--last-failed
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    および--failed-first
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    です。 これらのフラグのデータがキャッシュにどのように保存されるかを見てみましょう。 
  --last-failed
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    および--failed-first
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    オプションのヘルプテキストと、いくつかのcache
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    オプションを--failed-first
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ます。 
$ pytest --help ... --lf, --last-failed rerun only the tests that failed at the last run (or all if none failed) --ff, --failed-first run all tests but run the last failures first. This may re-order tests and thus lead to repeated fixture setup/teardown --cache-show show cache contents, don t perform collection or tests --cache-clear remove all cache contents at start of test run. ...
それらの動作を確認するには、次の2つのテストを使用します。
 def test_this_passes(): assert 1 == 1 def test_this_fails(): assert 1 == 2
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
       関数名を表示するには--verbose
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    を使用して実行し、スタックトレースを非表示にするには--tb=no
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    を使用します。 
$ cd /path/to/code/ch4/cache $ pytest --verbose --tb=no test_pass_fail.py ==================== test session starts ==================== collected 2 items test_pass_fail.py::test_this_passes PASSED test_pass_fail.py::test_this_fails FAILED ============ 1 failed, 1 passed in 0.05 seconds =============
  --ff
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    または--failed-first
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    フラグを--ff
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    して再度実行すると、以前に失敗したテストが最初に実行され、次にセッション全体が実行されます。 
$ pytest --verbose --tb=no --ff test_pass_fail.py ==================== test session starts ==================== run-last-failure: rerun last 1 failures first collected 2 items test_pass_fail.py::test_this_fails FAILED test_pass_fail.py::test_this_passes PASSED ============ 1 failed, 1 passed in 0.04 seconds =============
 または、 --lf
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    または--last-failed
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    を使用して、前回失敗したテストのみを実行できます。 
$ pytest --verbose --tb=no --lf test_pass_fail.py ==================== test session starts ==================== run-last-failure: rerun last 1 failures collected 2 items test_pass_fail.py::test_this_fails FAILED ==================== 1 tests deselected ===================== ========== 1 failed, 1 deselected in 0.05 seconds ===========
 クラッシュデータの保存方法と同じメカニズムの使用方法を説明する前に、 --lf
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    および--ff
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    値をさらに明確にする別の例を見てみましょう。 
以下は、1つの失敗を伴うパラメーター化されたテストです。
ch4 /キャッシュ/ test_few_failures.py
 """Demonstrate -lf and -ff with failing tests.""" import pytest from pytest import approx testdata = [ # x, y, expected (1.01, 2.01, 3.02), (1e25, 1e23, 1.1e25), (1.23, 3.21, 4.44), (0.1, 0.2, 0.3), (1e25, 1e24, 1.1e25) ] @pytest.mark.parametrize("x,y,expected", testdata) def test_a(x, y, expected): """Demo approx().""" sum_ = x + y assert sum_ == approx(expected)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      そして出力では:
$ cd /path/to/code/ch4/cache $ pytest -q test_few_failures.py .F... ====================== FAILURES ====================== _________________________ test_a[1e+25-1e+23-1.1e+25] _________________________ x = 1e+25, y = 1e+23, expected = 1.1e+25 @pytest.mark.parametrize("x,y,expected", testdata) def test_a(x, y, expected): """Demo approx().""" sum_ = x + y > assert sum_ == approx(expected) E assert 1.01e+25 == 1.1e+25 ± 1.1e+19 E + where 1.1e+25 ± 1.1e+19 = approx(1.1e+25) test_few_failures.py:17: AssertionError 1 failed, 4 passed in 0.06 seconds
すぐに問題を特定できるかもしれません。 しかし、テストがより長く、より複雑であり、ここで何が間違っているかはそれほど明白ではないと想像してみましょう。 もう一度テストを実行して、エラーを確認します。 テストケースはコマンドラインで指定できます。
$ pytest -q "test_few_failures.py::test_a[1e+25-1e+23-1.1e+25]"
  コピー/貼り付け(コピー/貼り付け )をしたくない場合、または再起動したい不幸なケースがいくつかある場合--lf
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     、 --lf
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    はるかに簡単です。 実際にテストの失敗をデバッグしている場合、状況を緩和する可能性のある別のフラグは--showlocals
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     、または略して-l
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    です。 
$ pytest -q --lf -l test_few_failures.py F ====================== FAILURES ====================== _________________________ test_a[1e+25-1e+23-1.1e+25] _________________________ x = 1e+25, y = 1e+23, expected = 1.1e+25 @pytest.mark.parametrize("x,y,expected", testdata) def test_a(x, y, expected): """Demo approx().""" sum_ = x + y > assert sum_ == approx(expected) E assert 1.01e+25 == 1.1e+25 ± 1.1e+19 E + where 1.1e+25 ± 1.1e+19 = approx(1.1e+25) expected = 1.1e+25 sum_ = 1.01e+25 x = 1e+25 y = 1e+23 test_few_failures.py:17: AssertionError ================= 4 tests deselected ================= 1 failed, 4 deselected in 0.05 seconds
失敗の理由はより明白であるはずです。
 前回テストが失敗したことを覚えておくために、ちょっとしたトリックがあります。  pytestは最後のテストセッションからのテストエラー情報を保存し、-- --cache-show
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    保存された情報を表示できます。 
$ pytest --cache-show ===================== test session starts ====================== ------------------------- cache values ------------------------- cache/lastfailed contains: {'test_few_failures.py::test_a[1e+25-1e+23-1.1e+25]': True} ================= no tests ran in 0.00 seconds =================
または、キャッシュディレクトリを確認できます。
$ cat .cache/v/cache/lastfailed { "test_few_failures.py::test_a[1e+25-1e+23-1.1e+25]": true }
  --clear-cache
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    スイッチを使用すると、セッションの前にキャッシュをクリアできます。 
 キャッシュは--lf
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    および--ff
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    だけでなく使用できます。 テストにかかった時間を記録し、時間を節約し、テストでエラーを報告する次回の記録を作成するフィクスチャを作成しましょう。前回のテストの2倍の時間がかかります。 
キャッシュフィクスチャのインターフェイスはシンプルです。
cache.get(key, default) cache.set(key, value)
 慣例により、キー名はアプリケーションまたはプラグインの名前で始まり、その後に/
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    が続き、キー名セクションは/
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    区切られます。 格納する値は、 .cache directory
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    表されるため、 jsonに変換される任意のものにすることができます。 
テスト時間を修正するために使用されるフィクスチャは次のとおりです。
 @pytest.fixture(autouse=True) def check_duration(request, cache): key = 'duration/' + request.node.nodeid.replace(':', '_') #   (nodeid)    #      .cache #    -     start_time = datetime.datetime.now() yield stop_time = datetime.datetime.now() this_duration = (stop_time - start_time).total_seconds() last_duration = cache.get(key, None) cache.set(key, this_duration) if last_duration is not None: errorstring = "       2-  " assert this_duration <= last_duration * 2, errorstring
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      フィクスチャはautouseであるため、テストから参照する必要はありません。 要求オブジェクトは、キーで使用するノードIDを取得するために使用されます。 nodeidは、パラメーター化されたテストでも機能する一意の識別子です。 キャッシュの適切な居住者になるように、「duration /」というキーを追加します。 上記のコードは、テスト関数の前に実行されます。 yieldの後のコードは、テスト関数の後に実行されます。
ここで、異なる時間間隔をとるいくつかのテストが必要です。
 @pytest.mark.parametrize('i', range(5)) def test_slow_stuff(i): time.sleep(random.random())
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
       おそらくこのための一連のテストを書きたくないので、 random
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    とパラメーター化を使用して、1秒よりも短いランダムな時間スリープするテストを簡単に生成しました。 これがどのように機能するかを数回見てみましょう。 
$ cd /path/to/code/ch4/cache $ pytest -q --cache-clear test_slower.py ..... 5 passed in 2.10 seconds $ pytest -q --tb=line test_slower.py ...E..E =================================== ERRORS ==================================== ___________________ ERROR at teardown of test_slow_stuff[1] ___________________ E AssertionError: test duration over 2x last duration assert 0.35702 <= (0.148009 * 2) ___________________ ERROR at teardown of test_slow_stuff[4] ___________________ E AssertionError: test duration over 2x last duration assert 0.888051 <= (0.324019 * 2) 5 passed, 2 error in 3.17 seconds
まあ、それは楽しかったです。 キャッシュの内容を見てみましょう。
$ pytest -q --cache-show -------------------------------- cache values --------------------------------- cache\lastfailed contains: {'test_slower.py::test_slow_stuff[2]': True, 'test_slower.py::test_slow_stuff[4]': True} cache\nodeids contains: ['test_slower.py::test_slow_stuff[0]', 'test_slower.py::test_slow_stuff[1]', 'test_slower.py::test_slow_stuff[2]', 'test_slower.py::test_slow_stuff[3]', 'test_slower.py::test_slow_stuff[4]'] cache\stepwise contains: [] duration\test_slower.py__test_slow_stuff[0] contains: 0.958055 duration\test_slower.py__test_slow_stuff[1] contains: 0.214012 duration\test_slower.py__test_slow_stuff[2] contains: 0.19001 duration\test_slower.py__test_slow_stuff[3] contains: 0.725041 duration\test_slower.py__test_slow_stuff[4] contains: 0.836048 no tests ran in 0.03 seconds
 キャッシュデータ名のプレフィックスにより、 duration
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    データをキャッシュデータとは別に簡単に表示できます。 ただし、 lastfailed
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    機能が単一のキャッシュエントリで機能することは興味深いことlastfailed
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     。 期間データは、テストごとに1つのキャッシュエントリを占有します。  lastfailedの例に従って、データを1つのレコードに入れましょう。 
 テストごとに読み取りとキャッシュを行います。 フィクスチャを関数のスコープのフィクスチャに分割して、キャッシュの読み取りと書き込みを行うセッションのスコープの期間とフィクスチャを測定できます。 ただし、これを行うと、関数のスコープがあるためキャッシュフィクスチャを使用できません。幸いなことに、GitHubの実装をざっと見てみると、キャッシュフィクスチャが単にを返していることがわかりますrequest.config.cache
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    。それはあらゆる地域で利用可能です。
同じ機能の可能な再編成の1つを次に示します。
 Duration = namedtuple('Duration', ['current', 'last']) @pytest.fixture(scope='session') def duration_cache(request): key = 'duration/testdurations' d = Duration({}, request.config.cache.get(key, {})) yield d request.config.cache.set(key, d.current) @pytest.fixture(autouse=True) def check_duration(request, duration_cache): d = duration_cache nodeid = request.node.nodeid start_time = datetime.datetime.now() yield duration = (datetime.datetime.now() - start_time).total_seconds() d.current[nodeid] = duration if d.last.get(nodeid, None) is not None: errorstring = "test duration over 2x last duration" assert duration <= (d.last[nodeid] * 2), errorstring
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
        duration_cache
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       .       ,     ,    - .        ,     namedtuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Duration    current
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      last
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     .     namedtuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      test_duration
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,         .    ,   namedtuple
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        ,         d.current
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     .          . 
, :
$ pytest -q --cache-clear test_slower_2.py ..... 5 passed in 2.80 seconds $ pytest -q --tb=no test_slower_2.py ...EE.. 7 passed, 2 error in 3.21 seconds $ pytest -q --cache-show -------------------------------- cache values --------------------------------- cache\lastfailed contains: {'test_slower_2.py::test_slow_stuff[2]': True, 'test_slower_2.py::test_slow_stuff[3]': True} duration\testdurations contains: {'test_slower_2.py::test_slow_stuff[0]': 0.483028, 'test_slower_2.py::test_slow_stuff[1]': 0.198011, 'test_slower_2.py::test_slow_stuff[2]': 0.426024, 'test_slower_2.py::test_slow_stuff[3]': 0.762044, 'test_slower_2.py::test_slow_stuff[4]': 0.056003, 'test_slower_2.py::test_slow_stuff[5]': 0.18401, 'test_slower_2.py::test_slow_stuff[6]': 0.943054} no tests ran in 0.02 seconds
.
capsys
  capsys builtin
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        :   stdout  stderr   ,     .     stdout  stderr. 
, stdout:
ch4/cap/test_capsys.py
 def greeting(name): print('Hi, {}'.format(name))
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      , . - stdout. capsys:
ch4/cap/test_capsys.py
 def test_greeting(capsys): greeting('Earthling') out, err = capsys.readouterr() assert out == 'Hi, Earthling\n' assert err == '' greeting('Brian') greeting('Nerd') out, err = capsys.readouterr() assert out == 'Hi, Brian\nHi, Nerd\n' assert err == ''
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
        stdout
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      stderr
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       capsys.redouterr()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     .   —  ,      ,     . 
      stdout
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     .    ,   stderr
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     : 
 def yikes(problem): print('YIKES! {}'.format(problem), file=sys.stderr) def test_yikes(capsys): yikes('Out of coffee!') out, err = capsys.readouterr() assert out == '' assert 'Out of coffee!' in err
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
       pytest        .     print .            .  -s
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       ,      stdout    .    ,        ,      .   ,             pytest  ,    ,   .      capsys .    capsys.disabled()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,       . 
以下に例を示します。
ch4/cap/test_capsys.py
 def test_capsys_disabled(capsys): with capsys.disabled(): print('\nalways print this') #    print('normal print, usually captured') #  ,  
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      , 'always print this' :
$ cd /path/to/code/ch4/cap $ pytest -q test_capsys.py::test_capsys_disabled
    ,  always print this
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
            ,        capys.disabled()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     .   print —     print,  normal print, usually captured
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ( ,  ),    ,     -s
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,     --capture=no
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,   . 
monkeypatch
 "monkey patch" —         .    "monkey patching" —                ,      ,     .   monkeypatch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           .    ,   ,    ,  ,    .    ,       .   API  ,  monkeypatch    . 
  monkeypatch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       : 
-  
setattr(target, name, value=<notset>, raising=True)
: . -  
delattr(target, name=<notset>, raising=True)
: . -  
setitem(dic, name, value)
: . -  
delitem(dic, name, raising=True)
: . -  
setenv(name, value, prepend=None)
: . -  
delenv(name, raising=True)
: . -  
syspath_prepend(path)
: sys., Python. -  
chdir(path)
: . 
  raising
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      pytest,    ,     .  prepend
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      setenv()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       .   ,        + prepend + <old value>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     . 
monkeypatch , , dot- . , dot- . , cheese- :
ch4/monkey/cheese.py
 import os import json def read_cheese_preferences(): full_path = os.path.expanduser('~/.cheese.json') with open(full_path, 'r') as f: prefs = json.load(f) return prefs def write_cheese_preferences(prefs): full_path = os.path.expanduser('~/.cheese.json') with open(full_path, 'w') as f: json.dump(prefs, f, indent=4) def write_default_cheese_preferences(): write_cheese_preferences(_default_prefs) _default_prefs = { 'slicing': ['manchego', 'sharp cheddar'], 'spreadable': ['Saint Andre', 'camembert', 'bucheron', 'goat', 'humbolt fog', 'cambozola'], 'salads': ['crumbled feta'] }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
        ,      write_default_cheese_preferences()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     .  ,         .    ,    .        . 
      ,          . ,       read_cheese_preferences()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,    ,        write_default_cheese_preferences()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     : 
ch4/monkey/test_cheese.py
 def test_def_prefs_full(): cheese.write_default_cheese_preferences() expected = cheese._default_prefs actual = cheese.read_cheese_preferences() assert expected == actual
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      , , , cheese- . .
     HOME set
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     , os.path.expanduser()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      ~
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,       HOME
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     .       HOME
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,       : 
ch4/monkey/test_cheese.py
 def test_def_prefs_change_home(tmpdir, monkeypatch): monkeypatch.setenv('HOME', tmpdir.mkdir('home')) cheese.write_default_cheese_preferences() expected = cheese._default_prefs actual = cheese.read_cheese_preferences() assert expected == actual
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
          ,  HOME
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          .     -  expanduser()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,     ,    «On Windows, HOME and USERPROFILE will be used if set, otherwise a combination of….» . わあ!      ,    Windows.  ,     . 
  ,     HOME
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,   expanduser
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     : 
ch4/monkey/test_cheese.py
 def test_def_prefs_change_expanduser(tmpdir, monkeypatch): fake_home_dir = tmpdir.mkdir('home') monkeypatch.setattr(cheese.os.path, 'expanduser', (lambda x: x.replace('~', str(fake_home_dir)))) cheese.write_default_cheese_preferences() expected = cheese._default_prefs actual = cheese.read_cheese_preferences() assert expected == actual
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
          ,    cheese  os.path.expanduser()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
         -.         re.sub
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       ~
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        .    setenv()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      setattr()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          . , setitem()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     . 
 ,   ,  ,    .    ,      ,   write_default_cheese_preferences()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     : 
ch4/monkey/test_cheese.py
 def test_def_prefs_change_defaults(tmpdir, monkeypatch): #      fake_home_dir = tmpdir.mkdir('home') monkeypatch.setattr(cheese.os.path, 'expanduser', (lambda x: x.replace('~', str(fake_home_dir)))) cheese.write_default_cheese_preferences() defaults_before = copy.deepcopy(cheese._default_prefs) #     monkeypatch.setitem(cheese._default_prefs, 'slicing', ['provolone']) monkeypatch.setitem(cheese._default_prefs, 'spreadable', ['brie']) monkeypatch.setitem(cheese._default_prefs, 'salads', ['pepper jack']) defaults_modified = cheese._default_prefs #       cheese.write_default_cheese_preferences() #    actual = cheese.read_cheese_preferences() assert defaults_modified == actual assert defaults_modified != defaults_before
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
        _default_prefs
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     - ,    monkeypatch.setitem()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,        . 
   setenv()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     , setattr()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      setitem()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     .  del
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      .     ,      ,  - .    monkeypatch
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       . 
 syspath_prepend(path)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        sys.path
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,    ,            .          stub-.      monkeypatch.syspath_prepend()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,     ,      stub-. 
 chdir(path)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           .            ,      .        ,      ,    monkeypatch.chdir(the_tmpdir)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     . 
       monkeypatch    unittest.mock
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,      .      7 " pytest   "  . 125. 
doctest_namespace
  doctest     Python         docstrings   ,  ,   .    pytest      doctest   Python    --doctest-modules
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     .    doctest_namespace
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,      autouse ,       pytest     doctest .   docstrings    . 
 doctest_namespace
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
             ,    Python       . , numpy
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        import numpy as np
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     . 
    . ,       unnecessary_math.py
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       multiply()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      divide()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,    .  ,        docstring ,    docstrings : 
ch4/dt/1/unnecessary_math.py
 """ This module defines multiply(a, b) and divide(a, b). >>> import unnecessary_math as um Here's how you use multiply: >>> um.multiply(4, 3) 12 >>> um.multiply('a', 3) 'aaa' Here's how you use divide: >>> um.divide(10, 5) 2.0 """ def multiply(a, b): """ Returns a multiplied by b. >>> um.multiply(4, 3) 12 >>> um.multiply('a', 3) 'aaa' """ return a * b def divide(a, b): """ Returns a divided by b. >>> um.divide(10, 5) 2.0 """ return a / b
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
         unnecessary_math
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,    um
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      ,  import noecessary_math as um
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       -.   docstrings     import
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,     um
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     .   ,  pytest   docstring    .    docstring    ,    docstrings    : 
$ cd /path/to/code/ch4/dt/1 $ pytest -v --doctest-modules --tb=short unnecessary_math.py ============================= test session starts ============================= collected 3 items unnecessary_math.py::unnecessary_math PASSED unnecessary_math.py::unnecessary_math.divide FAILED unnecessary_math.py::unnecessary_math.multiply FAILED ================================== FAILURES =================================== ______________________ [doctest] unnecessary_math.divide ______________________ 034 035 Returns a divided by b. 036 037 >>> um.divide(10, 5) UNEXPECTED EXCEPTION: NameError("name 'um' is not defined",) Traceback (most recent call last): ... File "<doctest unnecessary_math.divide[0]>", line 1, in <module> NameError: name 'um' is not defined ... _____________________ [doctest] unnecessary_math.multiply _____________________ 022 023 Returns a multiplied by b. 024 025 >>> um.multiply(4, 3) UNEXPECTED EXCEPTION: NameError("name 'um' is not defined",) Traceback (most recent call last): ... File "<doctest unnecessary_math.multiply[0]>", line 1, in <module> NameError: name 'um' is not defined /path/to/code/ch4/dt/1/unnecessary_math.py:23: UnexpectedException ================ 2 failed, 1 passed in 0.03 seconds =================
     -  import
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       docstring: 
ch4/dt/2/unnecessary_math.py
 """ This module defines multiply(a, b) and divide(a, b). >>> import unnecessary_math as um Here's how you use multiply: >>> um.multiply(4, 3) 12 >>> um.multiply('a', 3) 'aaa' Here's how you use divide: >>> um.divide(10, 5) 2.0 """ def multiply(a, b): """ Returns a multiplied by b. >>> import unnecessary_math as um >>> um.multiply(4, 3) 12 >>> um.multiply('a', 3) 'aaa' """ return a * b def divide(a, b): """ Returns a divided by b. >>> import unnecessary_math as um >>> um.divide(10, 5) 2.0 """ return a / b
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      :
$ cd /path/to/code/ch4/dt/2 $ pytest -v --doctest-modules --tb=short unnecessary_math.py ============================= test session starts ============================= collected 3 items unnecessary_math.py::unnecessary_math PASSED [ 33%] unnecessary_math.py::unnecessary_math.divide PASSED [ 66%] unnecessary_math.py::unnecessary_math.multiply PASSED [100%] ===================== 3 passed in 0.03 seconds ======================
docstrings .
   doctest_namespace
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,   autouse
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       conftest.py
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      ,      : 
ch4/dt/3/conftest.py
 import pytest import unnecessary_math @pytest.fixture(autouse=True) def add_um(doctest_namespace): doctest_namespace['um'] = unnecessary_math
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
         pytest   um
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      doctest_namespace
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,     unnecessary_math
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     .     conftest.py,  doctests,     conftest.py    um
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     . 
doctest pytest 7 " pytest " . 125.
recwarn
   recwarn
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        ,   .  Python    ,     ,    ,      . , ,      ,         ,      .             : 
ch4/test_warnings.py
 import warnings import pytest def lame_function(): warnings.warn("Please stop using this", DeprecationWarning) # rest of function
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      , :
ch4/test_warnings.py
 def test_lame_function(recwarn): lame_function() assert len(recwarn) == 1 w = recwarn.pop() assert w.category == DeprecationWarning assert str(w.message) == 'Please stop using this'
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
        recwarn    ,        category
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     (), message
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     (), filename
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ( )  lineno
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ( ),    . 
      .   ,     ,      ,     .      recwarn.clear()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,     ,      . 
    recwarn
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     , pytest      pytest.warns()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     : 
ch4/test_warnings.py
 def test_lame_function_2(): with pytest.warns(None) as warning_list: lame_function() assert len(warning_list) == 1 w = warning_list.pop() assert w.category == DeprecationWarning assert str(w.message) == 'Please stop using this'
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
         pytest.warns()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
             .  recwarn
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        pytest.warns()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       ,    ,  ,    . 
-   
ch4/cache/test_slower.py
autouse
,check_duration()
.ch3/tasks_proj/tests/conftest.py
. - 第3章のテストを実行します。
 - 非常に高速なテストの場合、2倍高速は依然として非常に高速です。2倍ではなく、フィクスチャを変更して、0.1秒と最後の継続時間の2倍を確認します。
 - 変更されたフィクスチャでpytestを実行します。結果は合理的ですか?
 
次は何ですか
この章では、組み込みのpytestフィクスチャをいくつか見てきました。次に、プラグインについてさらに詳しく検討します。大きなプラグインを書くことのニュアンスは、それ自体が本になることがあります。ただし、小さなカスタムプラグインは、pytestエコシステムの一部です。
  