342 lines
22 KiB
HTML
342 lines
22 KiB
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>1.8. Implementation and Customization of py.test — py lib v1.0.0b1 documentation</title>
|
|
<link rel="stylesheet" href="_static/default.css" type="text/css" />
|
|
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
|
<script type="text/javascript">
|
|
var DOCUMENTATION_OPTIONS = {
|
|
URL_ROOT: '',
|
|
VERSION: '1.0.0b1',
|
|
COLLAPSE_MODINDEX: false,
|
|
FILE_SUFFIX: '.html',
|
|
HAS_SOURCE: true
|
|
};
|
|
</script>
|
|
<script type="text/javascript" src="_static/jquery.js"></script>
|
|
<script type="text/javascript" src="_static/doctools.js"></script>
|
|
<link rel="top" title="py lib v1.0.0b1 documentation" href="index.html" />
|
|
<link rel="up" title="1. py.test" href="test.html" />
|
|
<link rel="next" title="2. py.execnet" href="execnet.html" />
|
|
<link rel="prev" title="1.7. Working Examples" href="test-examples.html" />
|
|
</head>
|
|
<body>
|
|
<div class="related">
|
|
<h3>Navigation</h3>
|
|
<ul>
|
|
<li class="right" style="margin-right: 10px">
|
|
<a href="genindex.html" title="General Index"
|
|
accesskey="I">index</a></li>
|
|
<li class="right" >
|
|
<a href="execnet.html" title="2. py.execnet"
|
|
accesskey="N">next</a> |</li>
|
|
<li class="right" >
|
|
<a href="test-examples.html" title="1.7. Working Examples"
|
|
accesskey="P">previous</a> |</li>
|
|
<li><a href="index.html">py lib v1.0.0b1 documentation</a> »</li>
|
|
<li><a href="test.html" accesskey="U">1. py.test</a> »</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="document">
|
|
<div class="documentwrapper">
|
|
<div class="bodywrapper">
|
|
<div class="body">
|
|
|
|
<div class="section" id="implementation-and-customization-of-py-test">
|
|
<h1>1.8. Implementation and Customization of <tt class="docutils literal"><span class="pre">py.test</span></tt><a class="headerlink" href="#implementation-and-customization-of-py-test" title="Permalink to this headline">¶</a></h1>
|
|
<div class="section" id="collecting-and-running-tests-implementation-remarks">
|
|
<span id="basicpicture"></span><h2>1.8.1. Collecting and running tests / implementation remarks<a class="headerlink" href="#collecting-and-running-tests-implementation-remarks" title="Permalink to this headline">¶</a></h2>
|
|
<p>In order to customize <tt class="docutils literal"><span class="pre">py.test</span></tt> it’s good to understand
|
|
its basic architure (WARNING: these are not guaranteed
|
|
yet to stay the way they are now!):</p>
|
|
<div class="highlight-python"><pre> ___________________
|
|
| |
|
|
| Collector |
|
|
|___________________|
|
|
/ \
|
|
| Item.run()
|
|
| ^
|
|
receive test Items /
|
|
| /execute test Item
|
|
| /
|
|
___________________/
|
|
| |
|
|
| Session |
|
|
|___________________|
|
|
|
|
.............................
|
|
. conftest.py configuration .
|
|
. cmdline options .
|
|
.............................</pre>
|
|
</div>
|
|
<p>The <em>Session</em> basically receives test <em>Items</em> from a <em>Collector</em>,
|
|
and executes them via the <tt class="docutils literal"><span class="pre">Item.run()</span></tt> method. It monitors
|
|
the outcome of the test and reports about failures and successes.</p>
|
|
<div class="section" id="collectors-and-the-test-collection-process">
|
|
<span id="collection-process"></span><h3>1.8.1.1. Collectors and the test collection process<a class="headerlink" href="#collectors-and-the-test-collection-process" title="Permalink to this headline">¶</a></h3>
|
|
<p>The collecting process is iterative, i.e. the session
|
|
traverses and generates a <em>collector tree</em>. Here is an example of such
|
|
a tree, generated with the command <tt class="docutils literal"><span class="pre">py.test</span> <span class="pre">--collectonly</span> <span class="pre">py/xmlobj</span></tt>:</p>
|
|
<div class="highlight-python"><pre><Directory 'xmlobj'>
|
|
<Directory 'testing'>
|
|
<Module 'test_html.py' (py.__.xmlobj.testing.test_html)>
|
|
<Function 'test_html_name_stickyness'>
|
|
<Function 'test_stylenames'>
|
|
<Function 'test_class_None'>
|
|
<Function 'test_alternating_style'>
|
|
<Module 'test_xml.py' (py.__.xmlobj.testing.test_xml)>
|
|
<Function 'test_tag_with_text'>
|
|
<Function 'test_class_identity'>
|
|
<Function 'test_tag_with_text_and_attributes'>
|
|
<Function 'test_tag_with_subclassed_attr_simple'>
|
|
<Function 'test_tag_nested'>
|
|
<Function 'test_tag_xmlname'></pre>
|
|
</div>
|
|
<p>By default all directories not starting with a dot are traversed,
|
|
looking for <tt class="docutils literal"><span class="pre">test_*.py</span></tt> and <tt class="docutils literal"><span class="pre">*_test.py</span></tt> files. Those files
|
|
are imported under their <a class="reference internal" href="#package-name">package name</a>.</p>
|
|
<p>The Module collector looks for test functions
|
|
and test classes and methods. Test functions and methods
|
|
are prefixed <tt class="docutils literal"><span class="pre">test</span></tt> by default. Test classes must
|
|
start with a capitalized <tt class="docutils literal"><span class="pre">Test</span></tt> prefix.</p>
|
|
</div>
|
|
<div class="section" id="test-items-are-collectors-as-well">
|
|
<span id="collector-api"></span><h3>1.8.1.2. test items are collectors as well<a class="headerlink" href="#test-items-are-collectors-as-well" title="Permalink to this headline">¶</a></h3>
|
|
<p>To make the reporting life simple for the session object
|
|
items offer a <tt class="docutils literal"><span class="pre">run()</span></tt> method as well. In fact the session
|
|
distinguishes “collectors” from “items” solely by interpreting
|
|
their return value. If it is a list, then we recurse into
|
|
it, otherwise we consider the “test” as passed.</p>
|
|
</div>
|
|
<div class="section" id="constructing-the-package-name-for-test-modules">
|
|
<span id="package-name"></span><h3>1.8.1.3. constructing the package name for test modules<a class="headerlink" href="#constructing-the-package-name-for-test-modules" title="Permalink to this headline">¶</a></h3>
|
|
<p>Test modules are imported under their fully qualified
|
|
name. Given a filesystem <tt class="docutils literal"><span class="pre">fspath</span></tt> it is constructed as follows:</p>
|
|
<ul class="simple">
|
|
<li>walk the directories up to the last one that contains
|
|
an <tt class="docutils literal"><span class="pre">__init__.py</span></tt> file.</li>
|
|
<li>perform <tt class="docutils literal"><span class="pre">sys.path.insert(0,</span> <span class="pre">basedir)</span></tt>.</li>
|
|
<li>import the root package as <tt class="docutils literal"><span class="pre">root</span></tt></li>
|
|
<li>determine the fully qualified name for <tt class="docutils literal"><span class="pre">fspath</span></tt> by either:<ul>
|
|
<li>calling <tt class="docutils literal"><span class="pre">root.__pkg__.getimportname(fspath)</span></tt> if the
|
|
<tt class="docutils literal"><span class="pre">__pkg__</span></tt> exists.` or</li>
|
|
<li>otherwise use the relative path of the module path to
|
|
the base dir and turn slashes into dots and strike
|
|
the trailing <tt class="docutils literal"><span class="pre">.py</span></tt>.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="customizing-the-testing-process">
|
|
<h2>1.8.2. Customizing the testing process<a class="headerlink" href="#customizing-the-testing-process" title="Permalink to this headline">¶</a></h2>
|
|
<div class="section" id="writing-conftest-py-files">
|
|
<h3>1.8.2.1. writing conftest.py files<a class="headerlink" href="#writing-conftest-py-files" title="Permalink to this headline">¶</a></h3>
|
|
<p>You may put conftest.py files containing project-specific
|
|
configuration in your project’s root directory, it’s usually
|
|
best to put it just into the same directory level as your
|
|
topmost <tt class="docutils literal"><span class="pre">__init__.py</span></tt>. In fact, <tt class="docutils literal"><span class="pre">py.test</span></tt> performs
|
|
an “upwards” search starting from the directory that you specify
|
|
to be tested and will lookup configuration values right-to-left.
|
|
You may have options that reside e.g. in your home directory
|
|
but note that project specific settings will be considered
|
|
first. There is a flag that helps you debugging your
|
|
conftest.py configurations:</p>
|
|
<div class="highlight-python"><div class="highlight"><pre><span class="n">py</span><span class="o">.</span><span class="n">test</span> <span class="o">--</span><span class="n">traceconfig</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="customizing-the-collecting-and-running-process">
|
|
<h3>1.8.2.2. customizing the collecting and running process<a class="headerlink" href="#customizing-the-collecting-and-running-process" title="Permalink to this headline">¶</a></h3>
|
|
<p>To introduce different test items you can create
|
|
one or more <tt class="docutils literal"><span class="pre">conftest.py</span></tt> files in your project.
|
|
When the collection process traverses directories
|
|
and modules the default collectors will produce
|
|
custom Collectors and Items if they are found
|
|
in a local <tt class="docutils literal"><span class="pre">conftest.py</span></tt> file.</p>
|
|
<div class="section" id="example-perform-additional-rest-checks">
|
|
<h4>1.8.2.2.1. example: perform additional ReST checks<a class="headerlink" href="#example-perform-additional-rest-checks" title="Permalink to this headline">¶</a></h4>
|
|
<p>With your custom collectors or items you can completely
|
|
derive from the standard way of collecting and running
|
|
tests in a localized manner. Let’s look at an example.
|
|
If you invoke <tt class="docutils literal"><span class="pre">py.test</span> <span class="pre">--collectonly</span> <span class="pre">py/documentation</span></tt>
|
|
then you get:</p>
|
|
<div class="highlight-python"><pre><DocDirectory 'documentation'>
|
|
<DocDirectory 'example'>
|
|
<DocDirectory 'pytest'>
|
|
<Module 'test_setup_flow_example.py' (test_setup_flow_example)>
|
|
<Class 'TestStateFullThing'>
|
|
<Instance '()'>
|
|
<Function 'test_42'>
|
|
<Function 'test_23'>
|
|
<ReSTChecker 'TODO.txt'>
|
|
<ReSTSyntaxTest 'TODO.txt'>
|
|
<LinkCheckerMaker 'checklinks'>
|
|
<ReSTChecker 'api.txt'>
|
|
<ReSTSyntaxTest 'api.txt'>
|
|
<LinkCheckerMaker 'checklinks'>
|
|
<CheckLink 'getting-started.html'>
|
|
...</pre>
|
|
</div>
|
|
<p>In <tt class="docutils literal"><span class="pre">py/documentation/conftest.py</span></tt> you find the following
|
|
customization:</p>
|
|
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">DocDirectory</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">collect</span><span class="o">.</span><span class="n">Directory</span><span class="p">):</span>
|
|
|
|
<span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|
<span class="n">results</span> <span class="o">=</span> <span class="nb">super</span><span class="p">(</span><span class="n">DocDirectory</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
|
|
<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">fspath</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="s">'*.txt'</span><span class="p">,</span> <span class="n">sort</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
|
|
<span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">basename</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">results</span>
|
|
|
|
<span class="k">def</span> <span class="nf">join</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
|
|
<span class="k">if</span> <span class="ow">not</span> <span class="n">name</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">'.txt'</span><span class="p">):</span>
|
|
<span class="k">return</span> <span class="nb">super</span><span class="p">(</span><span class="n">DocDirectory</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
|
|
<span class="n">p</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fspath</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
|
|
<span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="nb">file</span><span class="o">=</span><span class="mf">1</span><span class="p">):</span>
|
|
<span class="k">return</span> <span class="n">ReSTChecker</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">parent</span><span class="o">=</span><span class="bp">self</span><span class="p">)</span>
|
|
|
|
<span class="n">Directory</span> <span class="o">=</span> <span class="n">DocDirectory</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>The existence of the ‘Directory’ name in the
|
|
<tt class="docutils literal"><span class="pre">pypy/documentation/conftest.py</span></tt> module makes the collection
|
|
process defer to our custom “DocDirectory” collector. We extend
|
|
the set of collected test items by <tt class="docutils literal"><span class="pre">ReSTChecker</span></tt> instances
|
|
which themselves create <tt class="docutils literal"><span class="pre">ReSTSyntaxTest</span></tt> and <tt class="docutils literal"><span class="pre">LinkCheckerMaker</span></tt>
|
|
items. All of this instances (need to) follow the <a class="reference internal" href="#collector-api">collector API</a>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="customizing-the-reporting-of-test-failures">
|
|
<h3>1.8.2.3. Customizing the reporting of Test Failures<a class="headerlink" href="#customizing-the-reporting-of-test-failures" title="Permalink to this headline">¶</a></h3>
|
|
<p>XXX implement Item.repr_run and Item.repr_path for your test items</p>
|
|
</div>
|
|
<div class="section" id="writing-new-assertion-methods">
|
|
<h3>1.8.2.4. Writing new assertion methods<a class="headerlink" href="#writing-new-assertion-methods" title="Permalink to this headline">¶</a></h3>
|
|
<p>XXX __tracebackhide__, and use “print”</p>
|
|
</div>
|
|
<div class="section" id="customizing-the-collection-process-in-a-module">
|
|
<h3>1.8.2.5. Customizing the collection process in a module<a class="headerlink" href="#customizing-the-collection-process-in-a-module" title="Permalink to this headline">¶</a></h3>
|
|
<blockquote>
|
|
REPEATED WARNING: details of the collection and running process are
|
|
still subject to refactorings and thus details will change.
|
|
If you are customizing py.test at “Item” level then you
|
|
definitely want to be subscribed to the <a class="reference external" href="http://codespeak.net/mailman/listinfo/py-dev">py-dev mailing list</a>
|
|
to follow ongoing development.</blockquote>
|
|
<p>If you have a module where you want to take responsibility for
|
|
collecting your own test Items and possibly even for executing
|
|
a test then you can provide <a class="reference external" href="test-features.html#generative-tests">generative tests</a> that yield
|
|
callables and possibly arguments as a tuple. This is especially
|
|
useful for calling application test machinery with different
|
|
parameter sets but counting each of the calls as a separate
|
|
tests.</p>
|
|
<p>The other extension possibility is about
|
|
specifying a custom test <tt class="docutils literal"><span class="pre">Item</span></tt> class which
|
|
is responsible for setting up and executing an underlying
|
|
test. Or you can extend the collection process for a whole
|
|
directory tree by putting Items in a <tt class="docutils literal"><span class="pre">conftest.py</span></tt> configuration file.
|
|
The collection process dynamically consults the <em>chain of conftest.py</em>
|
|
modules to determine collectors and items at <tt class="docutils literal"><span class="pre">Directory</span></tt>, <tt class="docutils literal"><span class="pre">Module</span></tt>,
|
|
<tt class="docutils literal"><span class="pre">Class</span></tt>, <tt class="docutils literal"><span class="pre">Function</span></tt> or <tt class="docutils literal"><span class="pre">Generator</span></tt> level respectively.</p>
|
|
</div>
|
|
<div class="section" id="customizing-execution-of-functions">
|
|
<h3>1.8.2.6. Customizing execution of Functions<a class="headerlink" href="#customizing-execution-of-functions" title="Permalink to this headline">¶</a></h3>
|
|
<ul class="simple">
|
|
<li><tt class="docutils literal"><span class="pre">py.test.collect.Function</span></tt> test items control execution
|
|
of a test function. <tt class="docutils literal"><span class="pre">function.run()</span></tt> will get called by the
|
|
session in order to actually run a test. The method is responsible
|
|
for performing proper setup/teardown (“Test Fixtures”) for a
|
|
Function test.</li>
|
|
<li><tt class="docutils literal"><span class="pre">Function.execute(target,</span> <span class="pre">*args)</span></tt> methods are invoked by
|
|
the default <tt class="docutils literal"><span class="pre">Function.run()</span></tt> to actually execute a python
|
|
function with the given (usually empty set of) arguments.</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sphinxsidebar">
|
|
<div class="sphinxsidebarwrapper">
|
|
<h3><a href="index.html">Table Of Contents</a></h3>
|
|
<ul>
|
|
<li><a class="reference external" href="">1.8. Implementation and Customization of <tt class="docutils literal"><span class="pre">py.test</span></tt></a><ul>
|
|
<li><a class="reference external" href="#collecting-and-running-tests-implementation-remarks">1.8.1. Collecting and running tests / implementation remarks</a><ul>
|
|
<li><a class="reference external" href="#collectors-and-the-test-collection-process">1.8.1.1. Collectors and the test collection process</a></li>
|
|
<li><a class="reference external" href="#test-items-are-collectors-as-well">1.8.1.2. test items are collectors as well</a></li>
|
|
<li><a class="reference external" href="#constructing-the-package-name-for-test-modules">1.8.1.3. constructing the package name for test modules</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a class="reference external" href="#customizing-the-testing-process">1.8.2. Customizing the testing process</a><ul>
|
|
<li><a class="reference external" href="#writing-conftest-py-files">1.8.2.1. writing conftest.py files</a></li>
|
|
<li><a class="reference external" href="#customizing-the-collecting-and-running-process">1.8.2.2. customizing the collecting and running process</a><ul>
|
|
<li><a class="reference external" href="#example-perform-additional-rest-checks">1.8.2.2.1. example: perform additional ReST checks</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a class="reference external" href="#customizing-the-reporting-of-test-failures">1.8.2.3. Customizing the reporting of Test Failures</a></li>
|
|
<li><a class="reference external" href="#writing-new-assertion-methods">1.8.2.4. Writing new assertion methods</a></li>
|
|
<li><a class="reference external" href="#customizing-the-collection-process-in-a-module">1.8.2.5. Customizing the collection process in a module</a></li>
|
|
<li><a class="reference external" href="#customizing-execution-of-functions">1.8.2.6. Customizing execution of Functions</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
|
|
<h4>Previous topic</h4>
|
|
<p class="topless"><a href="test-examples.html"
|
|
title="previous chapter">1.7. Working Examples</a></p>
|
|
<h4>Next topic</h4>
|
|
<p class="topless"><a href="execnet.html"
|
|
title="next chapter">2. py.execnet</a></p>
|
|
<h3>This Page</h3>
|
|
<ul class="this-page-menu">
|
|
<li><a href="_sources/impl-test.txt"
|
|
rel="nofollow">Show Source</a></li>
|
|
</ul>
|
|
<div id="searchbox" style="display: none">
|
|
<h3>Quick search</h3>
|
|
<form class="search" action="search.html" method="get">
|
|
<input type="text" name="q" size="18" />
|
|
<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="related">
|
|
<h3>Navigation</h3>
|
|
<ul>
|
|
<li class="right" style="margin-right: 10px">
|
|
<a href="genindex.html" title="General Index"
|
|
>index</a></li>
|
|
<li class="right" >
|
|
<a href="execnet.html" title="2. py.execnet"
|
|
>next</a> |</li>
|
|
<li class="right" >
|
|
<a href="test-examples.html" title="1.7. Working Examples"
|
|
>previous</a> |</li>
|
|
<li><a href="index.html">py lib v1.0.0b1 documentation</a> »</li>
|
|
<li><a href="test.html" >1. py.test</a> »</li>
|
|
</ul>
|
|
</div>
|
|
<div class="footer">
|
|
© Copyright 2009, Holger Krekel.
|
|
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.7.
|
|
</div>
|
|
</body>
|
|
</html> |