<!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="Mysetup パターン: アプリケーションに特化したテストフィクスチャ" href="mysetup.html" /> <link rel="prev" title="py.test によるテスト失敗時のレポートのデモ" href="reportingdemo.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="mysetup.html" title="Mysetup パターン: アプリケーションに特化したテストフィクスチャ" accesskey="N">次へ</a> |</li> <li class="right" > <a href="reportingdemo.html" title="py.test によるテスト失敗時のレポートのデモ" 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="#id2">コマンドラインオプションでテスト関数に違う値を渡す</a></li> <li><a class="reference internal" href="#id3">コマンドラインオプションを動的に追加</a></li> <li><a class="reference internal" href="#excontrolskip">コマンドラインオプションでテストのスキップを制御</a></li> <li><a class="reference internal" href="#id5">統合的なアサーションヘルパーの作成</a></li> <li><a class="reference internal" href="#py-test">py.test で実行していることを検出</a></li> <li><a class="reference internal" href="#id6">テストレポートヘッダーに情報を追加</a></li> <li><a class="reference internal" href="#id7">テスト実行のプロファイリング</a></li> </ul> </li> </ul> <h4>前のトピックへ</h4> <p class="topless"><a href="reportingdemo.html" title="前の章へ">py.test によるテスト失敗時のレポートのデモ</a></p> <h4>次のトピックへ</h4> <p class="topless"><a href="mysetup.html" title="次の章へ">Mysetup パターン: アプリケーションに特化したテストフィクスチャ</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="id1"> <h1>基本的なパターンと例<a class="headerlink" href="#id1" title="このヘッドラインへのパーマリンク">¶</a></h1> <div class="section" id="id2"> <h2>コマンドラインオプションでテスト関数に違う値を渡す<a class="headerlink" href="#id2" title="このヘッドラインへのパーマリンク">¶</a></h2> <p>コマンドラインオプションで制御するテストを書きたいと仮定します。これを実現する基本的な方法は次の通りです:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># test_sample.py の内容</span> <span class="k">def</span> <span class="nf">test_answer</span><span class="p">(</span><span class="n">cmdopt</span><span class="p">):</span> <span class="k">if</span> <span class="n">cmdopt</span> <span class="o">==</span> <span class="s">"type1"</span><span class="p">:</span> <span class="k">print</span> <span class="p">(</span><span class="s">"first"</span><span class="p">)</span> <span class="k">elif</span> <span class="n">cmdopt</span> <span class="o">==</span> <span class="s">"type2"</span><span class="p">:</span> <span class="k">print</span> <span class="p">(</span><span class="s">"second"</span><span class="p">)</span> <span class="k">assert</span> <span class="mi">0</span> <span class="c"># 何が表示されるかを見るため</span> </pre></div> </div> <p>このためにはコマンドラインオプションを追加する必要があります。 <a class="reference internal" href="../funcargs.html#funcarg"><em>関数の引数</em></a> ファクトリーを使って <tt class="docutils literal"><span class="pre">cmdopt</span></tt> を提供します:</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">"--cmdopt"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s">"store"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s">"type1"</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s">"my option: type1 or type2"</span><span class="p">)</span> <span class="k">def</span> <span class="nf">pytest_funcarg__cmdopt</span><span class="p">(</span><span class="n">request</span><span class="p">):</span> <span class="k">return</span> <span class="n">request</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">cmdopt</span> </pre></div> </div> <p>先ほど作成したコマンドラインオプションを指定せずに実行してみましょう:</p> <div class="highlight-python"><pre>$ py.test -q test_sample.py collecting ... collected 1 items F ================================= FAILURES ================================= _______________________________ test_answer ________________________________ cmdopt = 'type1' def test_answer(cmdopt): if cmdopt == "type1": print ("first") elif cmdopt == "type2": print ("second") > assert 0 # 何が表示されるかを見るため E assert 0 test_sample.py:6: AssertionError ----------------------------- Captured stdout ------------------------------ first 1 failed in 0.01 seconds</pre> </div> <p>次はコマンドラインオプションを指定して実行します:</p> <div class="highlight-python"><pre>$ py.test -q --cmdopt=type2 collecting ... collected 1 items F ================================= FAILURES ================================= _______________________________ test_answer ________________________________ cmdopt = 'type2' def test_answer(cmdopt): if cmdopt == "type1": print ("first") elif cmdopt == "type2": print ("second") > assert 0 # 何が表示されるかを見るため E assert 0 test_sample.py:6: AssertionError ----------------------------- Captured stdout ------------------------------ second 1 failed in 0.01 seconds</pre> </div> <p>はい。基本的な使い方が分かりました。これ以外にも、テストの外部でコマンドラインオプションを処理して、別オブジェクトや複雑なオブジェクトを渡したいこともよくあります。次の例、もしくは現実の世界での例は <a class="reference internal" href="mysetup.html#mysetup"><em>Mysetup パターン: アプリケーションに特化したテストフィクスチャ</em></a> を参照してください。</p> </div> <div class="section" id="id3"> <h2>コマンドラインオプションを動的に追加<a class="headerlink" href="#id3" title="このヘッドラインへのパーマリンク">¶</a></h2> <p><a class="reference internal" href="../customize.html#confval-addopts"><tt class="xref std std-confval docutils literal"><span class="pre">addopts</span></tt></a> を使って、プロジェクトにコマンドラインオプションを静的に追加できます。静的に追加したコマンドラインオプションが処理される前に、そのコマンドラインオプションを動的に変更することもできます:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># conftest.py の内容</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="k">def</span> <span class="nf">pytest_cmdline_preparse</span><span class="p">(</span><span class="n">args</span><span class="p">):</span> <span class="k">if</span> <span class="s">'xdist'</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">modules</span><span class="p">:</span> <span class="c"># pytest-xdist プラグイン</span> <span class="kn">import</span> <span class="nn">multiprocessing</span> <span class="n">num</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">multiprocessing</span><span class="o">.</span><span class="n">cpu_count</span><span class="p">()</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="n">args</span><span class="p">[:]</span> <span class="o">=</span> <span class="p">[</span><span class="s">"-n"</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">num</span><span class="p">)]</span> <span class="o">+</span> <span class="n">args</span> </pre></div> </div> <p><a class="reference internal" href="../xdist.html#xdist"><em>xdist プラグイン</em></a> をインストール済みなら、毎回 CPU 数に近いサブプロセスを使ってテストを実行できます。空のディレクトリで上記の conftest.py を実行します:</p> <div class="highlight-python"><pre>$ py.test =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 gw0 I / gw1 I / gw2 I / gw3 I gw0 [0] / gw1 [0] / gw2 [0] / gw3 [0] scheduling tests via LoadScheduling ============================= in 0.52 seconds =============================</pre> </div> </div> <div class="section" id="excontrolskip"> <span id="id4"></span><h2>コマンドラインオプションでテストのスキップを制御<a class="headerlink" href="#excontrolskip" title="このヘッドラインへのパーマリンク">¶</a></h2> <p><tt class="docutils literal"><span class="pre">slow</span></tt> とマークされたテストのスキップを制御するコマンドラインオプション <tt class="docutils literal"><span class="pre">--runslow</span></tt> を追加する <tt class="docutils literal"><span class="pre">conftest.py</span></tt> があります:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># conftest.py の内容</span> <span class="kn">import</span> <span class="nn">pytest</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">"--runslow"</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 slow tests"</span><span class="p">)</span> <span class="k">def</span> <span class="nf">pytest_runtest_setup</span><span class="p">(</span><span class="n">item</span><span class="p">):</span> <span class="k">if</span> <span class="s">'slow'</span> <span class="ow">in</span> <span class="n">item</span><span class="o">.</span><span class="n">keywords</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">item</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">getvalue</span><span class="p">(</span><span class="s">"runslow"</span><span class="p">):</span> <span class="n">pytest</span><span class="o">.</span><span class="n">skip</span><span class="p">(</span><span class="s">"need --runslow option to run"</span><span class="p">)</span> </pre></div> </div> <p>テストモジュールは次のように書きます:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># test_module.py の内容</span> <span class="kn">import</span> <span class="nn">pytest</span> <span class="n">slow</span> <span class="o">=</span> <span class="n">pytest</span><span class="o">.</span><span class="n">mark</span><span class="o">.</span><span class="n">slow</span> <span class="k">def</span> <span class="nf">test_func_fast</span><span class="p">():</span> <span class="k">pass</span> <span class="nd">@slow</span> <span class="k">def</span> <span class="nf">test_func_slow</span><span class="p">():</span> <span class="k">pass</span> </pre></div> </div> <p>実行すると、”slow” テストがスキップされます:</p> <div class="highlight-python"><pre>$ py.test -rs # "-rs" は 's' の詳細をレポートします =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 collecting ... collected 2 items test_module.py .s ========================= short test summary info ========================== SKIP [1] /tmp/doc-exec-225/conftest.py:9: need --runslow option to run =================== 1 passed, 1 skipped in 0.01 seconds ====================</pre> </div> <p>もしくは <tt class="docutils literal"><span class="pre">slow</span></tt> とマークされたテストを実行します:</p> <div class="highlight-python"><pre>$ py.test --runslow =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 collecting ... collected 2 items test_module.py .. ========================= 2 passed in 0.01 seconds =========================</pre> </div> </div> <div class="section" id="id5"> <h2>統合的なアサーションヘルパーの作成<a class="headerlink" href="#id5" title="このヘッドラインへのパーマリンク">¶</a></h2> <p>テストから呼ばれるテストヘルパー関数があるなら、特定メッセージ付きでテストを失敗させる <tt class="docutils literal"><span class="pre">pytest.fail</span></tt> マーカーを使えます。 <tt class="docutils literal"><span class="pre">__tracebackhide__</span></tt> オプションをヘルパー関数内にセットすると、そのテストヘルパー関数はトレースバックを表示しなくなります。サンプルを紹介します:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># test_checkconfig.py の内容</span> <span class="kn">import</span> <span class="nn">pytest</span> <span class="k">def</span> <span class="nf">checkconfig</span><span class="p">(</span><span class="n">x</span><span class="p">):</span> <span class="n">__tracebackhide__</span> <span class="o">=</span> <span class="bp">True</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="s">"config"</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">"not configured: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span><span class="p">(</span><span class="n">x</span><span class="p">,))</span> <span class="k">def</span> <span class="nf">test_something</span><span class="p">():</span> <span class="n">checkconfig</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span> </pre></div> </div> <p><tt class="docutils literal"><span class="pre">__tracebackhide__</span></tt> 設定は、py.test のトレースバック表示に影響を与えます。 <tt class="docutils literal"><span class="pre">checkconfig</span></tt> 関数は、 <tt class="docutils literal"><span class="pre">--fulltrace</span></tt> コマンドラインオプションを指定しない限り、トレースバックを表示しません。この小さな関数を実行してみましょう:</p> <div class="highlight-python"><pre>$ py.test -q test_checkconfig.py collecting ... collected 1 items F ================================= FAILURES ================================= ______________________________ test_something ______________________________ def test_something(): > checkconfig(42) E Failed: not configured: 42 test_checkconfig.py:8: Failed 1 failed in 0.01 seconds</pre> </div> </div> <div class="section" id="py-test"> <h2>py.test で実行していることを検出<a class="headerlink" href="#py-test" title="このヘッドラインへのパーマリンク">¶</a></h2> <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_configure</span><span class="p">(</span><span class="n">config</span><span class="p">):</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="n">sys</span><span class="o">.</span><span class="n">_called_from_test</span> <span class="o">=</span> <span class="bp">True</span> <span class="k">def</span> <span class="nf">pytest_unconfigure</span><span class="p">(</span><span class="n">config</span><span class="p">):</span> <span class="k">del</span> <span class="n">sys</span><span class="o">.</span><span class="n">_called_from_test</span> </pre></div> </div> <p>アプリケーション内で <tt class="docutils literal"><span class="pre">sys._called_from_test</span></tt> というフラグをチェックします:</p> <div class="highlight-python"><pre>if hasattr(sys, '_called_from_test'): # テスト内から実行時に呼ばれる else: # "普通" のときに呼ばれる</pre> </div> <p>フラグを処理するために <tt class="docutils literal"><span class="pre">sys</span></tt> よりも独自のアプリケーションモジュールを使うのも良い考えです。</p> </div> <div class="section" id="id6"> <h2>テストレポートヘッダーに情報を追加<a class="headerlink" href="#id6" title="このヘッドラインへのパーマリンク">¶</a></h2> <p>py.test の実行時に追加の情報を表示するのは簡単です:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># conftest.py の内容</span> <span class="k">def</span> <span class="nf">pytest_report_header</span><span class="p">(</span><span class="n">config</span><span class="p">):</span> <span class="k">return</span> <span class="s">"project deps: mylib-1.1"</span> </pre></div> </div> <p>この関数はテストヘッダーに文字列を追加します:</p> <div class="highlight-python"><pre>$ py.test =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 project deps: mylib-1.1 collecting ... collected 0 items ============================= in 0.00 seconds =============================</pre> </div> <p>複数行に渡る情報を扱うなら文字列のリストも返せます。当然レポートの情報量も制御できます。例えば、必要なときに情報を表示するために <tt class="docutils literal"><span class="pre">config.option.verbose</span></tt> の値で切り分けます:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># conftest.py の内容</span> <span class="k">def</span> <span class="nf">pytest_report_header</span><span class="p">(</span><span class="n">config</span><span class="p">):</span> <span class="k">if</span> <span class="n">config</span><span class="o">.</span><span class="n">option</span><span class="o">.</span><span class="n">verbose</span> <span class="o">></span> <span class="mi">0</span><span class="p">:</span> <span class="k">return</span> <span class="p">[</span><span class="s">"info1: did you know that ..."</span><span class="p">,</span> <span class="s">"did you?"</span><span class="p">]</span> </pre></div> </div> <p>“–v” を指定して実行したときのみ追加の情報が表示されます:</p> <div class="highlight-python"><pre>$ py.test -v =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 -- /home/hpk/venv/0/bin/python info1: did you know that ... did you? collecting ... collected 0 items ============================= in 0.00 seconds =============================</pre> </div> <p>何も指定せずに実行すると何も表示しません:</p> <div class="highlight-python"><pre>$ py.test =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 collecting ... collected 0 items ============================= in 0.00 seconds =============================</pre> </div> </div> <div class="section" id="id7"> <h2>テスト実行のプロファイリング<a class="headerlink" href="#id7" title="このヘッドラインへのパーマリンク">¶</a></h2> <p>巨大なテストスイートの実行に時間がかかる場合、どのテストが最も遅いかを調べたいときがあります。擬似テストスイートで試してみましょう:</p> <div class="highlight-python"><div class="highlight"><pre><span class="c"># test_some_are_slow.py の内容</span> <span class="kn">import</span> <span class="nn">time</span> <span class="k">def</span> <span class="nf">test_funcfast</span><span class="p">():</span> <span class="k">pass</span> <span class="k">def</span> <span class="nf">test_funcslow1</span><span class="p">():</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> <span class="k">def</span> <span class="nf">test_funcslow2</span><span class="p">():</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.2</span><span class="p">)</span> </pre></div> </div> <p>次にようにして、どのテスト関数が最も遅いかをプロファイルできます:</p> <div class="highlight-python"><pre>$ py.test --durations=3 =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 collecting ... collected 3 items test_some_are_slow.py ... ========================= slowest 3 test durations ========================= 0.20s call test_some_are_slow.py::test_funcslow2 0.10s call test_some_are_slow.py::test_funcslow1 0.00s setup test_some_are_slow.py::test_funcslow2 ========================= 3 passed in 0.31 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="mysetup.html" title="Mysetup パターン: アプリケーションに特化したテストフィクスチャ" >次へ</a> |</li> <li class="right" > <a href="reportingdemo.html" title="py.test によるテスト失敗時のレポートのデモ" >前へ</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>