Current File : //usr/share/doc/pytest-2.7.0/html/en/example/parametrize.html
<!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>Parametrizing tests</title>
    
    <link rel="stylesheet" href="../_static/flasky.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.7.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>
    <link rel="shortcut icon" href="../_static/pytest1favi.ico"/>
    <link rel="top" title="None" href="../index.html" />
    <link rel="up" title="Usages and Examples" href="index.html" />
    <link rel="next" title="Working with custom markers" href="markers.html" />
    <link rel="prev" title="Basic patterns and examples" href="simple.html" />
   
  
  <meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9">

  </head>
  <body>
  
  

    <div class="related">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="markers.html" title="Working with custom markers"
             accesskey="N">next</a></li>
        <li class="right" >
          <a href="simple.html" title="Basic patterns and examples"
             accesskey="P">previous</a> |</li>
        <li><a href="../contents.html">pytest-2.7.0</a> &raquo;</li>
          <li><a href="index.html" accesskey="U">Usages and Examples</a> &raquo;</li> 
      </ul>
    </div>  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body">
            
  <div class="section" id="parametrizing-tests">
<span id="paramexamples"></span><h1>Parametrizing tests<a class="headerlink" href="#parametrizing-tests" title="Permalink to this headline">¶</a></h1>
<p><tt class="docutils literal"><span class="pre">pytest</span></tt> allows to easily parametrize test functions.
For basic docs, see <a class="reference internal" href="../parametrize.html#parametrize-basics"><em>Parametrizing fixtures and test functions</em></a>.</p>
<p>In the following we provide some examples using
the builtin mechanisms.</p>
<div class="section" id="generating-parameters-combinations-depending-on-command-line">
<h2>Generating parameters combinations, depending on command line<a class="headerlink" href="#generating-parameters-combinations-depending-on-command-line" title="Permalink to this headline">¶</a></h2>
<p>Let&#8217;s say we want to execute a test with different computation
parameters and the parameter range shall be determined by a command
line argument.  Let&#8217;s first write a simple (do-nothing) computation test:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># content of 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">&lt;</span> <span class="mi">4</span>
</pre></div>
</div>
<p>Now we add a test configuration like this:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># content of 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">&quot;--all&quot;</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s">&quot;store_true&quot;</span><span class="p">,</span>
        <span class="n">help</span><span class="o">=</span><span class="s">&quot;run all combinations&quot;</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">&#39;param1&#39;</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">&quot;param1&quot;</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>This means that we only run 2 tests if we do not pass <tt class="docutils literal"><span class="pre">--all</span></tt>:</p>
<div class="highlight-python"><pre>$ py.test -q test_compute.py
..
2 passed in 0.01 seconds</pre>
</div>
<p>We run only two computations, so we see two dots.
let&#8217;s run the full monty:</p>
<div class="highlight-python"><pre>$ py.test -q --all
....F
================================= FAILURES =================================
_____________________________ test_compute[4] ______________________________

param1 = 4

    def test_compute(param1):
&gt;       assert param1 &lt; 4
E       assert 4 &lt; 4

test_compute.py:3: AssertionError
1 failed, 4 passed in 0.01 seconds</pre>
</div>
<p>As expected when running the full range of <tt class="docutils literal"><span class="pre">param1</span></tt> values
we&#8217;ll get an error on the last one.</p>
</div>
<div class="section" id="different-options-for-test-ids">
<h2>Different options for test IDs<a class="headerlink" href="#different-options-for-test-ids" title="Permalink to this headline">¶</a></h2>
<p>pytest will build a string that is the test ID for each set of values in a
parametrized test. These IDs can be used with <tt class="docutils literal"><span class="pre">-k</span></tt> to select specific cases
to run, and they will also identify the specific case when one is failing.
Running pytest with <tt class="docutils literal"><span class="pre">--collect-only</span></tt> will show the generated IDs.</p>
<p>Numbers, strings, booleans and None will have their usual string representation
used in the test ID. For other objects, pytest will make a string based on
the argument name:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># contents of test_time.py</span>

<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timedelta</span>

<span class="n">testdata</span> <span class="o">=</span> <span class="p">[(</span><span class="n">datetime</span><span class="p">(</span><span class="mi">2001</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">12</span><span class="p">),</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2001</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">11</span><span class="p">),</span> <span class="n">timedelta</span><span class="p">(</span><span class="mi">1</span><span class="p">)),</span>
            <span class="p">(</span><span class="n">datetime</span><span class="p">(</span><span class="mi">2001</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">11</span><span class="p">),</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2001</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">12</span><span class="p">),</span> <span class="n">timedelta</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)),</span>
            <span class="p">]</span>


<span class="nd">@pytest.mark.parametrize</span><span class="p">(</span><span class="s">&quot;a,b,expected&quot;</span><span class="p">,</span> <span class="n">testdata</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">test_timedistance_v0</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">expected</span><span class="p">):</span>
    <span class="n">diff</span> <span class="o">=</span> <span class="n">a</span> <span class="o">-</span> <span class="n">b</span>
    <span class="k">assert</span> <span class="n">diff</span> <span class="o">==</span> <span class="n">expected</span>


<span class="nd">@pytest.mark.parametrize</span><span class="p">(</span><span class="s">&quot;a,b,expected&quot;</span><span class="p">,</span> <span class="n">testdata</span><span class="p">,</span> <span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s">&quot;forward&quot;</span><span class="p">,</span> <span class="s">&quot;backward&quot;</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">test_timedistance_v1</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">expected</span><span class="p">):</span>
    <span class="n">diff</span> <span class="o">=</span> <span class="n">a</span> <span class="o">-</span> <span class="n">b</span>
    <span class="k">assert</span> <span class="n">diff</span> <span class="o">==</span> <span class="n">expected</span>


<span class="k">def</span> <span class="nf">idfn</span><span class="p">(</span><span class="n">val</span><span class="p">):</span>
    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="p">(</span><span class="n">datetime</span><span class="p">,)):</span>
        <span class="c"># note this wouldn&#39;t show any hours/minutes/seconds</span>
        <span class="k">return</span> <span class="n">val</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">&#39;%Y%m</span><span class="si">%d</span><span class="s">&#39;</span><span class="p">)</span>


<span class="nd">@pytest.mark.parametrize</span><span class="p">(</span><span class="s">&quot;a,b,expected&quot;</span><span class="p">,</span> <span class="n">testdata</span><span class="p">,</span> <span class="n">ids</span><span class="o">=</span><span class="n">idfn</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">test_timedistance_v2</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">expected</span><span class="p">):</span>
    <span class="n">diff</span> <span class="o">=</span> <span class="n">a</span> <span class="o">-</span> <span class="n">b</span>
    <span class="k">assert</span> <span class="n">diff</span> <span class="o">==</span> <span class="n">expected</span>
</pre></div>
</div>
<p>In <tt class="docutils literal"><span class="pre">test_timedistance_v0</span></tt>, we let pytest generate the test IDs.</p>
<p>In <tt class="docutils literal"><span class="pre">test_timedistance_v1</span></tt>, we specified <tt class="docutils literal"><span class="pre">ids</span></tt> as a list of strings which were
used as the test IDs. These are succinct, but can be a pain to maintain.</p>
<p>In <tt class="docutils literal"><span class="pre">test_timedistance_v2</span></tt>, we specified <tt class="docutils literal"><span class="pre">ids</span></tt> as a function that can generate a
string representation to make part of the test ID. So our <tt class="docutils literal"><span class="pre">datetime</span></tt> values use the
label generated by <tt class="docutils literal"><span class="pre">idfn</span></tt>, but because we didn&#8217;t generate a label for <tt class="docutils literal"><span class="pre">timedelta</span></tt>
objects, they are still using the default pytest representation:</p>
<div class="highlight-python"><pre>$ py.test test_time.py --collect-only
=========================== test session starts ============================
platform linux -- Python 3.4.0 -- py-1.4.26 -- pytest-2.7.0
rootdir: /tmp/doc-exec-169, inifile:

=============================  in 0.00 seconds =============================
ERROR: file not found: test_time.py</pre>
</div>
</div>
<div class="section" id="a-quick-port-of-testscenarios">
<h2>A quick port of &#8220;testscenarios&#8221;<a class="headerlink" href="#a-quick-port-of-testscenarios" title="Permalink to this headline">¶</a></h2>
<p>Here is a quick port to run tests configured with <a class="reference external" href="http://pypi.python.org/pypi/testscenarios/">test scenarios</a>,
an add-on from Robert Collins for the standard unittest framework. We
only have to work a bit to construct the correct arguments for pytest&#8217;s
<a class="reference internal" href="../parametrize.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"># content of 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">scope</span><span class="o">=</span><span class="s">&quot;class&quot;</span><span class="p">)</span>

<span class="n">scenario1</span> <span class="o">=</span> <span class="p">(</span><span class="s">&#39;basic&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s">&#39;attribute&#39;</span><span class="p">:</span> <span class="s">&#39;value&#39;</span><span class="p">})</span>
<span class="n">scenario2</span> <span class="o">=</span> <span class="p">(</span><span class="s">&#39;advanced&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s">&#39;attribute&#39;</span><span class="p">:</span> <span class="s">&#39;value2&#39;</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_demo1</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>

    <span class="k">def</span> <span class="nf">test_demo2</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>this is a fully self-contained example which you can run with:</p>
<div class="highlight-python"><pre>$ py.test test_scenarios.py
=========================== test session starts ============================
platform linux -- Python 3.4.0 -- py-1.4.26 -- pytest-2.7.0
rootdir: /tmp/doc-exec-169, inifile:
collected 4 items

test_scenarios.py ....

========================= 4 passed in 0.01 seconds =========================</pre>
</div>
<p>If you just collect tests you&#8217;ll also nicely see &#8216;advanced&#8217; and &#8216;basic&#8217; as variants for the test function:</p>
<div class="highlight-python"><pre>$ py.test --collect-only test_scenarios.py
=========================== test session starts ============================
platform linux -- Python 3.4.0 -- py-1.4.26 -- pytest-2.7.0
rootdir: /tmp/doc-exec-169, inifile:
collected 4 items
&lt;Module 'test_scenarios.py'&gt;
  &lt;Class 'TestSampleWithScenarios'&gt;
    &lt;Instance '()'&gt;
      &lt;Function 'test_demo1[basic]'&gt;
      &lt;Function 'test_demo2[basic]'&gt;
      &lt;Function 'test_demo1[advanced]'&gt;
      &lt;Function 'test_demo2[advanced]'&gt;

=============================  in 0.01 seconds =============================</pre>
</div>
<p>Note that we told <tt class="docutils literal"><span class="pre">metafunc.parametrize()</span></tt> that your scenario values
should be considered class-scoped.  With pytest-2.3 this leads to a
resource-based ordering.</p>
</div>
<div class="section" id="deferring-the-setup-of-parametrized-resources">
<h2>Deferring the setup of parametrized resources<a class="headerlink" href="#deferring-the-setup-of-parametrized-resources" title="Permalink to this headline">¶</a></h2>
<p>The parametrization of test functions happens at collection
time.  It is a good idea to setup expensive resources like DB
connections or subprocess only when the actual test is run.
Here is a simple example how you can achieve that, first
the actual test requiring a <tt class="docutils literal"><span class="pre">db</span></tt> object:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># content of 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"># a dummy test</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">&quot;DB2&quot;</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">&quot;deliberately failing for demo purposes&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>We can now add a test configuration that generates two invocations of
the <tt class="docutils literal"><span class="pre">test_db_initialized</span></tt> function and also implements a factory that
creates a database object for the actual test invocations:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># content of conftest.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="k">if</span> <span class="s">&#39;db&#39;</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">&quot;db&quot;</span><span class="p">,</span> <span class="p">[</span><span class="s">&#39;d1&#39;</span><span class="p">,</span> <span class="s">&#39;d2&#39;</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">&quot;one database object&quot;</span>
<span class="k">class</span> <span class="nc">DB2</span><span class="p">:</span>
    <span class="s">&quot;alternative database object&quot;</span>

<span class="nd">@pytest.fixture</span>
<span class="k">def</span> <span class="nf">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">&quot;d1&quot;</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">&quot;d2&quot;</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">&quot;invalid internal test config&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Let&#8217;s first see how it looks like at collection time:</p>
<div class="highlight-python"><pre>$ py.test test_backends.py --collect-only
=========================== test session starts ============================
platform linux -- Python 3.4.0 -- py-1.4.26 -- pytest-2.7.0
rootdir: /tmp/doc-exec-169, inifile:
collected 2 items
&lt;Module 'test_backends.py'&gt;
  &lt;Function 'test_db_initialized[d1]'&gt;
  &lt;Function 'test_db_initialized[d2]'&gt;

=============================  in 0.00 seconds =============================</pre>
</div>
<p>And then when we run the test:</p>
<div class="highlight-python"><pre>$ py.test -q test_backends.py
.F
================================= FAILURES =================================
_________________________ test_db_initialized[d2] __________________________

db = &lt;conftest.DB2 object at 0x2b160a531f98&gt;

    def test_db_initialized(db):
        # a dummy test
        if db.__class__.__name__ == "DB2":
&gt;           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>The first invocation with <tt class="docutils literal"><span class="pre">db</span> <span class="pre">==</span> <span class="pre">&quot;DB1&quot;</span></tt> passed while the second with <tt class="docutils literal"><span class="pre">db</span> <span class="pre">==</span> <span class="pre">&quot;DB2&quot;</span></tt> failed.  Our <tt class="docutils literal"><span class="pre">db</span></tt> fixture function has instantiated each of the DB values during the setup phase while the <tt class="docutils literal"><span class="pre">pytest_generate_tests</span></tt> generated two according calls to the <tt class="docutils literal"><span class="pre">test_db_initialized</span></tt> during the collection phase.</p>
</div>
<div class="section" id="parametrizing-test-methods-through-per-class-configuration">
<h2>Parametrizing test methods through per-class configuration<a class="headerlink" href="#parametrizing-test-methods-through-per-class-configuration" title="Permalink to this headline">¶</a></h2>
<p>Here is an example <tt class="docutils literal"><span class="pre">pytest_generate_function</span></tt> function implementing a
parametrization scheme similar to Michael Foord&#8217;s <a class="reference external" href="http://code.google.com/p/unittest-ext/source/browse/trunk/params.py">unittest
parameterizer</a> but in a lot less code:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># content of ./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"># called once per each test function</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"># a map specifying multiple argument sets for a test method</span>
    <span class="n">params</span> <span class="o">=</span> <span class="p">{</span>
        <span class="s">&#39;test_equals&#39;</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">&#39;test_zerodivision&#39;</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">&quot;a/b&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Our test generator looks up a class-level definition which specifies which
argument sets to use for each test function.  Let&#8217;s run it:</p>
<div class="highlight-python"><pre>$ py.test -q
F..
================================= FAILURES =================================
________________________ TestClass.test_equals[1-2] ________________________

self = &lt;test_parametrize.TestClass object at 0x2ab66352a978&gt;, a = 1, b = 2

    def test_equals(self, a, b):
&gt;       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="indirect-parametrization-with-multiple-fixtures">
<h2>Indirect parametrization with multiple fixtures<a class="headerlink" href="#indirect-parametrization-with-multiple-fixtures" title="Permalink to this headline">¶</a></h2>
<p>Here is a stripped down real-life example of using parametrized
testing for testing serialization of objects between different python
interpreters.  We define a <tt class="docutils literal"><span class="pre">test_basic_objects</span></tt> function which
is to be run with different sets of arguments for its three arguments:</p>
<ul class="simple">
<li><tt class="docutils literal"><span class="pre">python1</span></tt>: first python interpreter, run to pickle-dump an object to a file</li>
<li><tt class="docutils literal"><span class="pre">python2</span></tt>: second interpreter, run to pickle-load an object from a file</li>
<li><tt class="docutils literal"><span class="pre">obj</span></tt>: object to be dumped/loaded</li>
</ul>
<div class="highlight-python"><div class="highlight"><pre><span class="sd">&quot;&quot;&quot;</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">&quot;&quot;&quot;</span>
<span class="kn">import</span> <span class="nn">py</span>
<span class="kn">import</span> <span class="nn">pytest</span>

<span class="n">pythonlist</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;python2.6&#39;</span><span class="p">,</span> <span class="s">&#39;python2.7&#39;</span><span class="p">,</span> <span class="s">&#39;python3.3&#39;</span><span class="p">]</span>
<span class="nd">@pytest.fixture</span><span class="p">(</span><span class="n">params</span><span class="o">=</span><span class="n">pythonlist</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">python1</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">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">&quot;data.pickle&quot;</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="nd">@pytest.fixture</span><span class="p">(</span><span class="n">params</span><span class="o">=</span><span class="n">pythonlist</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">python2</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">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">pytest</span><span class="o">.</span><span class="n">skip</span><span class="p">(</span><span class="s">&quot;</span><span class="si">%r</span><span class="s"> not found&quot;</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">&quot;dump.py&quot;</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">&quot;&quot;&quot;</span>
<span class="s">            import pickle</span>
<span class="s">            f = open(</span><span class="si">%r</span><span class="s">, &#39;wb&#39;)</span>
<span class="s">            s = pickle.dump(</span><span class="si">%r</span><span class="s">, f, protocol=2)</span>
<span class="s">            f.close()</span>
<span class="s">        &quot;&quot;&quot;</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">&quot;</span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s">&quot;</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">&quot;load.py&quot;</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">&quot;&quot;&quot;</span>
<span class="s">            import pickle</span>
<span class="s">            f = open(</span><span class="si">%r</span><span class="s">, &#39;rb&#39;)</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">        &quot;&quot;&quot;</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">&quot;</span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s">&quot;</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>

<span class="nd">@pytest.mark.parametrize</span><span class="p">(</span><span class="s">&quot;obj&quot;</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">&quot;obj == </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">obj</span><span class="p">)</span>
</pre></div>
</div>
<p>Running it results in some skips if we don&#8217;t have all the python interpreters installed and otherwise runs all combinations (5 interpreters times 5 interpreters times 3 objects to serialize/deserialize):</p>
<div class="highlight-python"><pre>. $ py.test -rs -q multipython.py
...........................
27 passed in 1.70 seconds</pre>
</div>
</div>
<div class="section" id="indirect-parametrization-of-optional-implementations-imports">
<h2>Indirect parametrization of optional implementations/imports<a class="headerlink" href="#indirect-parametrization-of-optional-implementations-imports" title="Permalink to this headline">¶</a></h2>
<p>If you want to compare the outcomes of several implementations of a given
API, you can write test functions that receive the already imported implementations
and get skipped in case the implementation is not importable/available.  Let&#8217;s
say we have a &#8220;base&#8221; implementation and the other (possibly optimized ones)
need to provide similar results:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># content of conftest.py</span>

<span class="kn">import</span> <span class="nn">pytest</span>

<span class="nd">@pytest.fixture</span><span class="p">(</span><span class="n">scope</span><span class="o">=</span><span class="s">&quot;session&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">basemod</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">pytest</span><span class="o">.</span><span class="n">importorskip</span><span class="p">(</span><span class="s">&quot;base&quot;</span><span class="p">)</span>

<span class="nd">@pytest.fixture</span><span class="p">(</span><span class="n">scope</span><span class="o">=</span><span class="s">&quot;session&quot;</span><span class="p">,</span> <span class="n">params</span><span class="o">=</span><span class="p">[</span><span class="s">&quot;opt1&quot;</span><span class="p">,</span> <span class="s">&quot;opt2&quot;</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">optmod</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">pytest</span><span class="o">.</span><span class="n">importorskip</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">param</span><span class="p">)</span>
</pre></div>
</div>
<p>And then a base implementation of a simple function:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># content of base.py</span>
<span class="k">def</span> <span class="nf">func1</span><span class="p">():</span>
    <span class="k">return</span> <span class="mi">1</span>
</pre></div>
</div>
<p>And an optimized version:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># content of opt1.py</span>
<span class="k">def</span> <span class="nf">func1</span><span class="p">():</span>
    <span class="k">return</span> <span class="mf">1.0001</span>
</pre></div>
</div>
<p>And finally a little test module:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># content of test_module.py</span>

<span class="k">def</span> <span class="nf">test_func1</span><span class="p">(</span><span class="n">basemod</span><span class="p">,</span> <span class="n">optmod</span><span class="p">):</span>
    <span class="k">assert</span> <span class="nb">round</span><span class="p">(</span><span class="n">basemod</span><span class="o">.</span><span class="n">func1</span><span class="p">(),</span> <span class="mi">3</span><span class="p">)</span> <span class="o">==</span> <span class="nb">round</span><span class="p">(</span><span class="n">optmod</span><span class="o">.</span><span class="n">func1</span><span class="p">(),</span> <span class="mi">3</span><span class="p">)</span>
</pre></div>
</div>
<p>If you run this with reporting for skips enabled:</p>
<div class="highlight-python"><pre>$ py.test -rs test_module.py
=========================== test session starts ============================
platform linux -- Python 3.4.0 -- py-1.4.26 -- pytest-2.7.0
rootdir: /tmp/doc-exec-169, inifile:
collected 2 items

test_module.py .s
========================= short test summary info ==========================
SKIP [1] /tmp/doc-exec-169/conftest.py:10: could not import 'opt2'

=================== 1 passed, 1 skipped in 0.01 seconds ====================</pre>
</div>
<p>You&#8217;ll see that we don&#8217;t have a <tt class="docutils literal"><span class="pre">opt2</span></tt> module and thus the second test run
of our <tt class="docutils literal"><span class="pre">test_func1</span></tt> was skipped.  A few notes:</p>
<ul class="simple">
<li>the fixture functions in the <tt class="docutils literal"><span class="pre">conftest.py</span></tt> file are &#8220;session-scoped&#8221; because we
don&#8217;t need to import more than once</li>
<li>if you have multiple test functions and a skipped import, you will see
the <tt class="docutils literal"><span class="pre">[1]</span></tt> count increasing in the report</li>
<li>you can put <a class="reference internal" href="../parametrize.html#pytest-mark-parametrize"><em>&#64;pytest.mark.parametrize</em></a> style
parametrization on the test functions to parametrize input/output
values as well.</li>
</ul>
</div>
</div>


          </div>
        </div>
      </div>
      <div class="sphinxsidebar">
        <div class="sphinxsidebarwrapper">
            <p class="logo"><a href="../contents.html">
              <img class="logo" src="../_static/pytest1.png" alt="Logo"/>
            </a></p><h3><a href="../contents.html">Table Of Contents</a></h3>

<ul>
  <li><a href="../index.html">Home</a></li>
  <li><a href="../contents.html">Contents</a></li>
  <li><a href="../getting-started.html">Install</a></li>
  <li><a href="index.html">Examples</a></li>
  <li><a href="../customize.html">Customize</a></li>
  <li><a href="../contact.html">Contact</a></li>
  <li><a href="../talks.html">Talks/Posts</a></li>
  <li><a href="../changelog.html">Changelog</a></li>
</ul>
  <hr>
  <ul>
<li><a class="reference internal" href="#">Parametrizing tests</a><ul>
<li><a class="reference internal" href="#generating-parameters-combinations-depending-on-command-line">Generating parameters combinations, depending on command line</a></li>
<li><a class="reference internal" href="#different-options-for-test-ids">Different options for test IDs</a></li>
<li><a class="reference internal" href="#a-quick-port-of-testscenarios">A quick port of &#8220;testscenarios&#8221;</a></li>
<li><a class="reference internal" href="#deferring-the-setup-of-parametrized-resources">Deferring the setup of parametrized resources</a></li>
<li><a class="reference internal" href="#parametrizing-test-methods-through-per-class-configuration">Parametrizing test methods through per-class configuration</a></li>
<li><a class="reference internal" href="#indirect-parametrization-with-multiple-fixtures">Indirect parametrization with multiple fixtures</a></li>
<li><a class="reference internal" href="#indirect-parametrization-of-optional-implementations-imports">Indirect parametrization of optional implementations/imports</a></li>
</ul>
</li>
</ul>
<h3>Related Topics</h3>
<ul>
  <li><a href="../contents.html">Documentation overview</a><ul>
  <li><a href="index.html">Usages and Examples</a><ul>
      <li>Previous: <a href="simple.html" title="previous chapter">Basic patterns and examples</a></li>
      <li>Next: <a href="markers.html" title="next chapter">Working with custom markers</a></li>
  </ul></li>
  </ul></li>
</ul><h3>Useful Links</h3>
<ul>
  <li><a href="../index.html">The pytest Website</a></li>
  <li><a href="../contributing.html">Contribution Guide</a></li>
  <li><a href="https://pypi.python.org/pypi/pytest">pytest @ PyPI</a></li>
  <li><a href="https://bitbucket.org/pytest-dev/pytest/">pytest @ Bitbucket</a></li>
  <li><a href="http://pytest.org/latest/plugins_index/index.html">3rd party plugins</a></li>
  <li><a href="https://bitbucket.org/pytest-dev/pytest/issues?status=new&status=open">Issue Tracker</a></li>
  <li><a href="http://pytest.org/latest/pytest.pdf">PDF Documentation</a>
</ul>

<div id="searchbox" style="display: none">
  <h3>Quick search</h3>
    <form class="search" action="../search.html" method="get">
      <input type="text" name="q" />
      <input type="submit" value="Go" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    <p class="searchtip" style="font-size: 90%">
    Enter search terms or a module, class or function name.
    </p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
      <div class="clearer"></div>
    </div>

  <div class="footer">
    &copy; Copyright 2014, holger krekel.
    Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>.
  </div>
  
<script type="text/javascript">

  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-7597274-13']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();

</script>

  </body>
</html>