<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>パラメーターテスト</title> <link rel="stylesheet" href="../_static/sphinxdoc.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <script type="text/javascript"> var DOCUMENTATION_OPTIONS = { URL_ROOT: '../', VERSION: '2.2.4.0', COLLAPSE_INDEX: false, FILE_SUFFIX: '.html', HAS_SOURCE: true }; </script> <script type="text/javascript" src="../_static/jquery.js"></script> <script type="text/javascript" src="../_static/underscore.js"></script> <script type="text/javascript" src="../_static/doctools.js"></script> <script type="text/javascript" src="../_static/translations.js"></script> <link rel="top" title="None" href="../index.html" /> <link rel="up" title="使用方法と例" href="index.html" /> <link rel="next" title="カスタムマーカーを使う" href="markers.html" /> <link rel="prev" title="Mysetup パターン: アプリケーションに特化したテストフィクスチャ" href="mysetup.html" /> </head> <body> <div class="related"> <h3>ナビゲーション</h3> <ul> <li class="right" style="margin-right: 10px"> <a href="../py-modindex.html" title="Pythonモジュール索引" >モジュール</a></li> <li class="right" > <a href="markers.html" title="カスタムマーカーを使う" accesskey="N">次へ</a> |</li> <li class="right" > <a href="mysetup.html" title="Mysetup パターン: アプリケーションに特化したテストフィクスチャ" accesskey="P">前へ</a> |</li> <li><a href="../contents.html">pytest-2.2.4.0</a> »</li> <li><a href="index.html" accesskey="U">使用方法と例</a> »</li> </ul> </div> <div class="sphinxsidebar"> <div class="sphinxsidebarwrapper"> <h3><a href="../contents.html">目次</a></h3> <ul> <li><a class="reference internal" href="#">パラメーターテスト</a><ul> <li><a class="reference internal" href="#parametrizemark">シンプルな “デコレーター” によるパラメーターテスト</a></li> <li><a class="reference internal" href="#id3">コマンドラインからパラメーターの組み合わせを作成</a></li> <li><a class="reference internal" href="#testscenarios">“testscenarios” の手早い移行</a></li> <li><a class="reference internal" href="#id4">パラメーター化されたリソースの遅延セットアップ</a></li> <li><a class="reference internal" href="#id5">クラス設定毎のテストメソッドのパラメーター渡し</a></li> <li><a class="reference internal" href="#id6">複数リソースでの間接的なパラメーター渡し</a></li> </ul> </li> </ul> <h4>前のトピックへ</h4> <p class="topless"><a href="mysetup.html" title="前の章へ">Mysetup パターン: アプリケーションに特化したテストフィクスチャ</a></p> <h4>次のトピックへ</h4> <p class="topless"><a href="markers.html" title="次の章へ">カスタムマーカーを使う</a></p> <div id="searchbox" style="display: none"> <h3>クイック検索</h3> <form class="search" action="../search.html" method="get"> <input type="text" name="q" /> <input type="submit" value="検索" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> <p class="searchtip" style="font-size: 90%"> モジュール、クラス、または関数名を入力してください </p> </div> <script type="text/javascript">$('#searchbox').show(0);</script> </div> </div> <div class="document"> <div class="documentwrapper"> <div class="bodywrapper"> <div class="body"> <div class="section" id="paramexamples"> <span id="id1"></span><h1>パラメーターテスト<a class="headerlink" href="#paramexamples" title="このヘッドラインへのパーマリンク">¶</a></h1> <p>py.test は、簡単にパラメーターをテスト関数へ渡せます。パラメーターテストを行うための組み込みの仕組みを使ったサンプルを紹介します。</p> <div class="section" id="parametrizemark"> <span id="id2"></span><h2>シンプルな “デコレーター” によるパラメーターテスト<a class="headerlink" href="#parametrizemark" title="このヘッドラインへのパーマリンク">¶</a></h2> <p class="versionadded"> <span class="versionmodified">バージョン 2.2 で追加.</span></p> <p>組み込みの <tt class="docutils literal"><span class="pre">pytest.mark.parametrize</span></tt> デコレーターは、直接、テスト関数の引数へパラメーターを渡せます。入力値を処理して、その結果として期待される出力値を比較したいテスト関数のサンプルを紹介します:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># test_expectation.py の内容</span> <span class="kn">import</span> <span class="nn">pytest</span> <span class="nd">@pytest.mark.parametrize</span><span class="p">((</span><span class="s">"input"</span><span class="p">,</span> <span class="s">"expected"</span><span class="p">),</span> <span class="p">[</span> <span class="p">(</span><span class="s">"3+5"</span><span class="p">,</span> <span class="mi">8</span><span class="p">),</span> <span class="p">(</span><span class="s">"2+4"</span><span class="p">,</span> <span class="mi">6</span><span class="p">),</span> <span class="p">(</span><span class="s">"6*9"</span><span class="p">,</span> <span class="mi">42</span><span class="p">),</span> <span class="p">])</span> <span class="k">def</span> <span class="nf">test_eval</span><span class="p">(</span><span class="nb">input</span><span class="p">,</span> <span class="n">expected</span><span class="p">):</span> <span class="k">assert</span> <span class="nb">eval</span><span class="p">(</span><span class="nb">input</span><span class="p">)</span> <span class="o">==</span> <span class="n">expected</span> </pre></div> </div> <p>テスト関数が3回呼び出され、そのテスト関数へ2つの引数をパラメーターとして渡します。実行してみましょう:</p> <div class="highlight-python"><pre>$ py.test -q collecting ... collected 3 items ..F ================================= FAILURES ================================= ____________________________ test_eval[6*9-42] _____________________________ input = '6*9', expected = 42 @pytest.mark.parametrize(("input", "expected"), [ ("3+5", 8), ("2+4", 6), ("6*9", 42), ]) def test_eval(input, expected): > assert eval(input) == expected E assert 54 == 42 E + where 54 = eval('6*9') test_expectation.py:8: AssertionError 1 failed, 2 passed in 0.01 seconds</pre> </div> <p>期待した通り、入力値/出力値の組み合わせの1つだけがこの単純なテスト関数を失敗させます。</p> <p>関数のグループをマークする方法は様々なやり方があるのに注意してください。詳細は <a class="reference internal" href="../mark.html#mark"><em>属性をもつテスト関数のマーク</em></a> を参照してください。</p> </div> <div class="section" id="id3"> <h2>コマンドラインからパラメーターの組み合わせを作成<a class="headerlink" href="#id3" title="このヘッドラインへのパーマリンク">¶</a></h2> <p>別のパラメーターでテストを実行したいときに、そのパラメーターの範囲はコマンドライン引数によって決まるものとしましょう。最初の簡単な (何もしない) テストを書いてみます:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># test_compute.py の内容</span> <span class="k">def</span> <span class="nf">test_compute</span><span class="p">(</span><span class="n">param1</span><span class="p">):</span> <span class="k">assert</span> <span class="n">param1</span> <span class="o"><</span> <span class="mi">4</span> </pre></div> </div> <p>次のようなテスト設定を追加します:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># conftest.py の内容</span> <span class="k">def</span> <span class="nf">pytest_addoption</span><span class="p">(</span><span class="n">parser</span><span class="p">):</span> <span class="n">parser</span><span class="o">.</span><span class="n">addoption</span><span class="p">(</span><span class="s">"--all"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s">"store_true"</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s">"run all combinations"</span><span class="p">)</span> <span class="k">def</span> <span class="nf">pytest_generate_tests</span><span class="p">(</span><span class="n">metafunc</span><span class="p">):</span> <span class="k">if</span> <span class="s">'param1'</span> <span class="ow">in</span> <span class="n">metafunc</span><span class="o">.</span><span class="n">fixturenames</span><span class="p">:</span> <span class="k">if</span> <span class="n">metafunc</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">option</span><span class="o">.</span><span class="n">all</span><span class="p">:</span> <span class="n">end</span> <span class="o">=</span> <span class="mi">5</span> <span class="k">else</span><span class="p">:</span> <span class="n">end</span> <span class="o">=</span> <span class="mi">2</span> <span class="n">metafunc</span><span class="o">.</span><span class="n">parametrize</span><span class="p">(</span><span class="s">"param1"</span><span class="p">,</span> <span class="nb">range</span><span class="p">(</span><span class="n">end</span><span class="p">))</span> </pre></div> </div> <p>これは <tt class="docutils literal"><span class="pre">--all</span></tt> を指定しない場合、2回だけテストを実行します:</p> <div class="highlight-python"><pre>$ py.test -q test_compute.py collecting ... collected 2 items .. 2 passed in 0.01 seconds</pre> </div> <p>2回だけテストを実行するので、ドットが2つ表示されます。では、全テストを実行してみましょう:</p> <div class="highlight-python"><pre>$ py.test -q --all collecting ... collected 5 items ....F ================================= FAILURES ================================= _____________________________ test_compute[4] ______________________________ param1 = 4 def test_compute(param1): > assert param1 < 4 E assert 4 < 4 test_compute.py:3: AssertionError 1 failed, 4 passed in 0.02 seconds</pre> </div> <p>期待した通り <tt class="docutils literal"><span class="pre">param1</span></tt> の全ての範囲値を実行すると、最後の1つがエラーになります。</p> </div> <div class="section" id="testscenarios"> <h2>“testscenarios” の手早い移行<a class="headerlink" href="#testscenarios" title="このヘッドラインへのパーマリンク">¶</a></h2> <p>Robert Collins による標準ライブラリの unittest フレームワークのアドオンである <a class="reference external" href="http://bazaar.launchpad.net/~lifeless/testscenarios/trunk/annotate/head%3A/doc/example.py">test scenarios</a> で設定されたテストを実行するために手早い移行方法を紹介します。pytest の <a class="reference internal" href="../funcargs.html#_pytest.python.Metafunc.parametrize" title="_pytest.python.Metafunc.parametrize"><tt class="xref py py-func docutils literal"><span class="pre">Metafunc.parametrize()</span></tt></a> へ渡す正しい引数を作成するために少しだけコーディングが必要です:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># test_scenarios.py の内容</span> <span class="k">def</span> <span class="nf">pytest_generate_tests</span><span class="p">(</span><span class="n">metafunc</span><span class="p">):</span> <span class="n">idlist</span> <span class="o">=</span> <span class="p">[]</span> <span class="n">argvalues</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">for</span> <span class="n">scenario</span> <span class="ow">in</span> <span class="n">metafunc</span><span class="o">.</span><span class="n">cls</span><span class="o">.</span><span class="n">scenarios</span><span class="p">:</span> <span class="n">idlist</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">scenario</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="n">items</span> <span class="o">=</span> <span class="n">scenario</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="n">argnames</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">items</span><span class="p">]</span> <span class="n">argvalues</span><span class="o">.</span><span class="n">append</span><span class="p">(([</span><span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">items</span><span class="p">]))</span> <span class="n">metafunc</span><span class="o">.</span><span class="n">parametrize</span><span class="p">(</span><span class="n">argnames</span><span class="p">,</span> <span class="n">argvalues</span><span class="p">,</span> <span class="n">ids</span><span class="o">=</span><span class="n">idlist</span><span class="p">)</span> <span class="n">scenario1</span> <span class="o">=</span> <span class="p">(</span><span class="s">'basic'</span><span class="p">,</span> <span class="p">{</span><span class="s">'attribute'</span><span class="p">:</span> <span class="s">'value'</span><span class="p">})</span> <span class="n">scenario2</span> <span class="o">=</span> <span class="p">(</span><span class="s">'advanced'</span><span class="p">,</span> <span class="p">{</span><span class="s">'attribute'</span><span class="p">:</span> <span class="s">'value2'</span><span class="p">})</span> <span class="k">class</span> <span class="nc">TestSampleWithScenarios</span><span class="p">:</span> <span class="n">scenarios</span> <span class="o">=</span> <span class="p">[</span><span class="n">scenario1</span><span class="p">,</span> <span class="n">scenario2</span><span class="p">]</span> <span class="k">def</span> <span class="nf">test_demo</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attribute</span><span class="p">):</span> <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">attribute</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> </pre></div> </div> <p>これはすぐ実行できる完全な自己完結型サンプルです:</p> <div class="highlight-python"><pre>$ py.test test_scenarios.py =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 collecting ... collected 2 items test_scenarios.py .. ========================= 2 passed in 0.01 seconds =========================</pre> </div> <p>ただテストを (実行せずに) 集めるだけなら、テスト関数の変数として ‘advanced’ と ‘basic’ もうまく表示されます:</p> <div class="highlight-python"><pre>$ py.test --collectonly test_scenarios.py =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 collecting ... collected 2 items <Module 'test_scenarios.py'> <Class 'TestSampleWithScenarios'> <Instance '()'> <Function 'test_demo[basic]'> <Function 'test_demo[advanced]'> ============================= in 0.00 seconds =============================</pre> </div> </div> <div class="section" id="id4"> <h2>パラメーター化されたリソースの遅延セットアップ<a class="headerlink" href="#id4" title="このヘッドラインへのパーマリンク">¶</a></h2> <p>テスト関数へのパラメーター渡しはコレクション時に発生します。実際にテストを実行するときのみ、DB コネクションやサブプロセスといった高価なリソースをセットアップするのは良い考えです。そういったテストを行う簡単なサンプルが次になります。最初のテストは <tt class="docutils literal"><span class="pre">db</span></tt> オブジェクトを要求します:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># test_backends.py の内容</span> <span class="kn">import</span> <span class="nn">pytest</span> <span class="k">def</span> <span class="nf">test_db_initialized</span><span class="p">(</span><span class="n">db</span><span class="p">):</span> <span class="c"># ダミーテスト</span> <span class="k">if</span> <span class="n">db</span><span class="o">.</span><span class="n">__class__</span><span class="o">.</span><span class="n">__name__</span> <span class="o">==</span> <span class="s">"DB2"</span><span class="p">:</span> <span class="n">pytest</span><span class="o">.</span><span class="n">fail</span><span class="p">(</span><span class="s">"deliberately failing for demo purposes"</span><span class="p">)</span> </pre></div> </div> <p><tt class="docutils literal"><span class="pre">test_db_initialized</span></tt> 関数の2回実行するようにテスト設定を追加します。さらに実際のテスト実行時にデータベースオブジェクトを作成するファクトリー関数も実装します:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># conftest.py の内容</span> <span class="k">def</span> <span class="nf">pytest_generate_tests</span><span class="p">(</span><span class="n">metafunc</span><span class="p">):</span> <span class="k">if</span> <span class="s">'db'</span> <span class="ow">in</span> <span class="n">metafunc</span><span class="o">.</span><span class="n">fixturenames</span><span class="p">:</span> <span class="n">metafunc</span><span class="o">.</span><span class="n">parametrize</span><span class="p">(</span><span class="s">"db"</span><span class="p">,</span> <span class="p">[</span><span class="s">'d1'</span><span class="p">,</span> <span class="s">'d2'</span><span class="p">],</span> <span class="n">indirect</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="k">class</span> <span class="nc">DB1</span><span class="p">:</span> <span class="s">"one database object"</span> <span class="k">class</span> <span class="nc">DB2</span><span class="p">:</span> <span class="s">"alternative database object"</span> <span class="k">def</span> <span class="nf">pytest_funcarg__db</span><span class="p">(</span><span class="n">request</span><span class="p">):</span> <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">param</span> <span class="o">==</span> <span class="s">"d1"</span><span class="p">:</span> <span class="k">return</span> <span class="n">DB1</span><span class="p">()</span> <span class="k">elif</span> <span class="n">request</span><span class="o">.</span><span class="n">param</span> <span class="o">==</span> <span class="s">"d2"</span><span class="p">:</span> <span class="k">return</span> <span class="n">DB2</span><span class="p">()</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"invalid internal test config"</span><span class="p">)</span> </pre></div> </div> <p>コレクション時に先ほどの設定がどうなるかを最初に見てみましょう:</p> <div class="highlight-python"><pre>$ py.test test_backends.py --collectonly =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 collecting ... collected 2 items <Module 'test_backends.py'> <Function 'test_db_initialized[d1]'> <Function 'test_db_initialized[d2]'> ============================= in 0.00 seconds =============================</pre> </div> <p>それからテストを実行します:</p> <div class="highlight-python"><pre>$ py.test -q test_backends.py collecting ... collected 2 items .F ================================= FAILURES ================================= _________________________ test_db_initialized[d2] __________________________ db = <conftest.DB2 instance at 0x1d4eb00> def test_db_initialized(db): # ダミーテスト if db.__class__.__name__ == "DB2": > pytest.fail("deliberately failing for demo purposes") E Failed: deliberately failing for demo purposes test_backends.py:6: Failed 1 failed, 1 passed in 0.01 seconds</pre> </div> <p>最初の <tt class="docutils literal"><span class="pre">db</span> <span class="pre">==</span> <span class="pre">"DB1"</span></tt> による実行が成功したのに対して、2番目の <tt class="docutils literal"><span class="pre">db</span> <span class="pre">==</span> <span class="pre">"DB2"</span></tt> は失敗しました。 <tt class="docutils literal"><span class="pre">pytest_funcarg__db</span></tt> ファクトリーは、セットアップフェーズのときにそれぞれの DB 値をインスタンス化しました。一方 <tt class="docutils literal"><span class="pre">pytest_generate_tests</span></tt> は、コレクションフェーズのときに2回の <tt class="docutils literal"><span class="pre">test_db_initialized</span></tt> 呼び出しを生成しました。</p> </div> <div class="section" id="id5"> <h2>クラス設定毎のテストメソッドのパラメーター渡し<a class="headerlink" href="#id5" title="このヘッドラインへのパーマリンク">¶</a></h2> <p>Michael Foord の <a class="reference external" href="http://code.google.com/p/unittest-ext/source/browse/trunk/params.py">unittest parameterizer</a> とよく似ていますが、それよりもずっと少ないコードでパラメーターを渡す仕組みを実装する <tt class="docutils literal"><span class="pre">pytest_generate_function</span></tt> 関数のサンプルがあります:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># ./test_parametrize.py の内容</span> <span class="kn">import</span> <span class="nn">pytest</span> <span class="k">def</span> <span class="nf">pytest_generate_tests</span><span class="p">(</span><span class="n">metafunc</span><span class="p">):</span> <span class="c"># それぞれのテスト関数毎に1回呼び出される</span> <span class="n">funcarglist</span> <span class="o">=</span> <span class="n">metafunc</span><span class="o">.</span><span class="n">cls</span><span class="o">.</span><span class="n">params</span><span class="p">[</span><span class="n">metafunc</span><span class="o">.</span><span class="n">function</span><span class="o">.</span><span class="n">__name__</span><span class="p">]</span> <span class="n">argnames</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">funcarglist</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="n">metafunc</span><span class="o">.</span><span class="n">parametrize</span><span class="p">(</span><span class="n">argnames</span><span class="p">,</span> <span class="p">[[</span><span class="n">funcargs</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="k">for</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">argnames</span><span class="p">]</span> <span class="k">for</span> <span class="n">funcargs</span> <span class="ow">in</span> <span class="n">funcarglist</span><span class="p">])</span> <span class="k">class</span> <span class="nc">TestClass</span><span class="p">:</span> <span class="c"># テストメソッドのために複数の引数セットを指定するディクショナリ</span> <span class="n">params</span> <span class="o">=</span> <span class="p">{</span> <span class="s">'test_equals'</span><span class="p">:</span> <span class="p">[</span><span class="nb">dict</span><span class="p">(</span><span class="n">a</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">b</span><span class="o">=</span><span class="mi">2</span><span class="p">),</span> <span class="nb">dict</span><span class="p">(</span><span class="n">a</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">b</span><span class="o">=</span><span class="mi">3</span><span class="p">),</span> <span class="p">],</span> <span class="s">'test_zerodivision'</span><span class="p">:</span> <span class="p">[</span><span class="nb">dict</span><span class="p">(</span><span class="n">a</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">b</span><span class="o">=</span><span class="mi">0</span><span class="p">),</span> <span class="p">],</span> <span class="p">}</span> <span class="k">def</span> <span class="nf">test_equals</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span> <span class="k">assert</span> <span class="n">a</span> <span class="o">==</span> <span class="n">b</span> <span class="k">def</span> <span class="nf">test_zerodivision</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span> <span class="n">pytest</span><span class="o">.</span><span class="n">raises</span><span class="p">(</span><span class="ne">ZeroDivisionError</span><span class="p">,</span> <span class="s">"a/b"</span><span class="p">)</span> </pre></div> </div> <p>テストジェネレーターは、それぞれのテストメソッドへどの引数セットを渡すかを特定するクラスレベルの定義を調べます。実行してみましょう:</p> <div class="highlight-python"><pre>$ py.test -q collecting ... collected 3 items F.. ================================= FAILURES ================================= ________________________ TestClass.test_equals[1-2] ________________________ self = <test_parametrize.TestClass instance at 0x10d2e18>, a = 1, b = 2 def test_equals(self, a, b): > assert a == b E assert 1 == 2 test_parametrize.py:18: AssertionError 1 failed, 2 passed in 0.01 seconds</pre> </div> </div> <div class="section" id="id6"> <h2>複数リソースでの間接的なパラメーター渡し<a class="headerlink" href="#id6" title="このヘッドラインへのパーマリンク">¶</a></h2> <p>別々の Python インタープリターで実行し、シリアライズ化を検証するのにパラメーターテストを使う、実際の世界でのサンプルを解説します。次の3つの引数を全組み合わせで実行する <tt class="docutils literal"><span class="pre">test_basic_objects</span></tt> 関数を定義します。</p> <ul class="simple"> <li><tt class="docutils literal"><span class="pre">python1</span></tt> : 1番目の Python インタープリター、オブジェクトをファイルへ pickle-dump するために実行</li> <li><tt class="docutils literal"><span class="pre">python2</span></tt> : 2番目の Python インタープリター、ファイルからオブジェクトを pickle-load するために実行</li> <li><tt class="docutils literal"><span class="pre">obj</span></tt> : ダンプしたり読み込むためのオブジェクト</li> </ul> <div class="highlight-python"><div class="highlight"><pre><span class="sd">"""</span> <span class="sd">module containing a parametrized tests testing cross-python</span> <span class="sd">serialization via the pickle module.</span> <span class="sd">"""</span> <span class="kn">import</span> <span class="nn">py</span><span class="o">,</span> <span class="nn">pytest</span> <span class="n">pythonlist</span> <span class="o">=</span> <span class="p">[</span><span class="s">'python2.4'</span><span class="p">,</span> <span class="s">'python2.5'</span><span class="p">,</span> <span class="s">'python2.6'</span><span class="p">,</span> <span class="s">'python2.7'</span><span class="p">,</span> <span class="s">'python2.8'</span><span class="p">]</span> <span class="k">def</span> <span class="nf">pytest_generate_tests</span><span class="p">(</span><span class="n">metafunc</span><span class="p">):</span> <span class="c"># we parametrize all "python1" and "python2" arguments to iterate</span> <span class="c"># over the python interpreters of our list above - the actual</span> <span class="c"># setup and lookup of interpreters in the python1/python2 factories</span> <span class="c"># respectively.</span> <span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">metafunc</span><span class="o">.</span><span class="n">fixturenames</span><span class="p">:</span> <span class="k">if</span> <span class="n">arg</span> <span class="ow">in</span> <span class="p">(</span><span class="s">"python1"</span><span class="p">,</span> <span class="s">"python2"</span><span class="p">):</span> <span class="n">metafunc</span><span class="o">.</span><span class="n">parametrize</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="n">pythonlist</span><span class="p">,</span> <span class="n">indirect</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="nd">@pytest.mark.parametrize</span><span class="p">(</span><span class="s">"obj"</span><span class="p">,</span> <span class="p">[</span><span class="mi">42</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{</span><span class="mi">1</span><span class="p">:</span><span class="mi">3</span><span class="p">},])</span> <span class="k">def</span> <span class="nf">test_basic_objects</span><span class="p">(</span><span class="n">python1</span><span class="p">,</span> <span class="n">python2</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span> <span class="n">python1</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="n">python2</span><span class="o">.</span><span class="n">load_and_is_true</span><span class="p">(</span><span class="s">"obj == </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">obj</span><span class="p">)</span> <span class="k">def</span> <span class="nf">pytest_funcarg__python1</span><span class="p">(</span><span class="n">request</span><span class="p">):</span> <span class="n">tmpdir</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">getfuncargvalue</span><span class="p">(</span><span class="s">"tmpdir"</span><span class="p">)</span> <span class="n">picklefile</span> <span class="o">=</span> <span class="n">tmpdir</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s">"data.pickle"</span><span class="p">)</span> <span class="k">return</span> <span class="n">Python</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">param</span><span class="p">,</span> <span class="n">picklefile</span><span class="p">)</span> <span class="k">def</span> <span class="nf">pytest_funcarg__python2</span><span class="p">(</span><span class="n">request</span><span class="p">):</span> <span class="n">python1</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">getfuncargvalue</span><span class="p">(</span><span class="s">"python1"</span><span class="p">)</span> <span class="k">return</span> <span class="n">Python</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">param</span><span class="p">,</span> <span class="n">python1</span><span class="o">.</span><span class="n">picklefile</span><span class="p">)</span> <span class="k">class</span> <span class="nc">Python</span><span class="p">:</span> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">version</span><span class="p">,</span> <span class="n">picklefile</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">pythonpath</span> <span class="o">=</span> <span class="n">py</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">local</span><span class="o">.</span><span class="n">sysfind</span><span class="p">(</span><span class="n">version</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">pythonpath</span><span class="p">:</span> <span class="n">py</span><span class="o">.</span><span class="n">test</span><span class="o">.</span><span class="n">skip</span><span class="p">(</span><span class="s">"</span><span class="si">%r</span><span class="s"> not found"</span> <span class="o">%</span><span class="p">(</span><span class="n">version</span><span class="p">,))</span> <span class="bp">self</span><span class="o">.</span><span class="n">picklefile</span> <span class="o">=</span> <span class="n">picklefile</span> <span class="k">def</span> <span class="nf">dumps</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span> <span class="n">dumpfile</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">picklefile</span><span class="o">.</span><span class="n">dirpath</span><span class="p">(</span><span class="s">"dump.py"</span><span class="p">)</span> <span class="n">dumpfile</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">py</span><span class="o">.</span><span class="n">code</span><span class="o">.</span><span class="n">Source</span><span class="p">(</span><span class="s">"""</span> <span class="s"> import pickle</span> <span class="s"> f = open(</span><span class="si">%r</span><span class="s">, 'wb')</span> <span class="s"> s = pickle.dump(</span><span class="si">%r</span><span class="s">, f)</span> <span class="s"> f.close()</span> <span class="s"> """</span> <span class="o">%</span> <span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">picklefile</span><span class="p">),</span> <span class="n">obj</span><span class="p">)))</span> <span class="n">py</span><span class="o">.</span><span class="n">process</span><span class="o">.</span><span class="n">cmdexec</span><span class="p">(</span><span class="s">"</span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">pythonpath</span><span class="p">,</span> <span class="n">dumpfile</span><span class="p">))</span> <span class="k">def</span> <span class="nf">load_and_is_true</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="p">):</span> <span class="n">loadfile</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">picklefile</span><span class="o">.</span><span class="n">dirpath</span><span class="p">(</span><span class="s">"load.py"</span><span class="p">)</span> <span class="n">loadfile</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">py</span><span class="o">.</span><span class="n">code</span><span class="o">.</span><span class="n">Source</span><span class="p">(</span><span class="s">"""</span> <span class="s"> import pickle</span> <span class="s"> f = open(</span><span class="si">%r</span><span class="s">, 'rb')</span> <span class="s"> obj = pickle.load(f)</span> <span class="s"> f.close()</span> <span class="s"> res = eval(</span><span class="si">%r</span><span class="s">)</span> <span class="s"> if not res:</span> <span class="s"> raise SystemExit(1)</span> <span class="s"> """</span> <span class="o">%</span> <span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">picklefile</span><span class="p">),</span> <span class="n">expression</span><span class="p">)))</span> <span class="k">print</span> <span class="p">(</span><span class="n">loadfile</span><span class="p">)</span> <span class="n">py</span><span class="o">.</span><span class="n">process</span><span class="o">.</span><span class="n">cmdexec</span><span class="p">(</span><span class="s">"</span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">pythonpath</span><span class="p">,</span> <span class="n">loadfile</span><span class="p">))</span> </pre></div> </div> <p>もし全ての Python インタープリターがインストールされていない場合、実行してもスキップされます。インストール済みの場合、全ての組み合わせが実行されます (5つのインタープリター * 5つのインタープリター * 3つのシリアライズ/デシリアライズするオブジェクト):</p> <div class="highlight-python"><pre>. $ py.test -rs -q multipython.py collecting ... collected 75 items ............sss............sss............sss............ssssssssssssssssss ========================= short test summary info ========================== SKIP [27] /home/hpk/p/pytest/doc/example/multipython.py:36: 'python2.8' not found 48 passed, 27 skipped in 1.71 seconds</pre> </div> </div> </div> </div> </div> </div> <div class="clearer"></div> </div> <div class="related"> <h3>ナビゲーション</h3> <ul> <li class="right" style="margin-right: 10px"> <a href="../py-modindex.html" title="Pythonモジュール索引" >モジュール</a></li> <li class="right" > <a href="markers.html" title="カスタムマーカーを使う" >次へ</a> |</li> <li class="right" > <a href="mysetup.html" title="Mysetup パターン: アプリケーションに特化したテストフィクスチャ" >前へ</a> |</li> <li><a href="../contents.html">pytest-2.2.4.0</a> »</li> <li><a href="index.html" >使用方法と例</a> »</li> </ul> </div> <div class="footer"> © Copyright 2011, holger krekel et alii. このドキュメントは <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3 で生成しました。 </div> </body> </html>