refine docs and docstrings, fix some small bits here and there while doing that.

This commit is contained in:
holger krekel 2010-11-18 14:56:16 +01:00
parent a698465487
commit 582486d531
20 changed files with 88 additions and 202 deletions

View File

@ -64,12 +64,16 @@ class DoctestItem(pytest.Item):
class DoctestTextfile(DoctestItem, pytest.File): class DoctestTextfile(DoctestItem, pytest.File):
def runtest(self): def runtest(self):
failed, tot = py.std.doctest.testfile( doctest = py.std.doctest
failed, tot = doctest.testfile(
str(self.fspath), module_relative=False, str(self.fspath), module_relative=False,
optionflags=doctest.ELLIPSIS,
raise_on_error=True, verbose=0) raise_on_error=True, verbose=0)
class DoctestModule(DoctestItem, pytest.File): class DoctestModule(DoctestItem, pytest.File):
def runtest(self): def runtest(self):
doctest = py.std.doctest
module = self.fspath.pyimport() module = self.fspath.pyimport()
failed, tot = py.std.doctest.testmod( failed, tot = doctest.testmod(
module, raise_on_error=True, verbose=0) module, raise_on_error=True, verbose=0,
optionflags=doctest.ELLIPSIS)

View File

@ -1,4 +1,4 @@
"""run test suites written for nose. """ """ run test suites written for nose. """
import pytest, py import pytest, py
import inspect import inspect

View File

@ -762,19 +762,28 @@ def raises(ExpectedException, *args, **kwargs):
If using Python 2.5 or above, you may use this function as a If using Python 2.5 or above, you may use this function as a
context manager:: context manager::
>>> with raises(ZeroDivisionError): >>> with raises(ZeroDivisionError):
... 1/0 ... 1/0
Or you can one of two forms: Or you can specify a callable by passing a to-be-called lambda::
if args[0] is callable: raise AssertionError if calling it with >>> raises(ZeroDivisionError, lambda: 1/0)
the remaining arguments does not raise the expected exception. <ExceptionInfo ...>
if args[0] is a string: raise AssertionError if executing the
the string in the calling scope does not raise expected exception. or you can specify an arbitrary callable with arguments::
examples:
>>> x = 5 >>> def f(x): return 1/x
>>> raises(TypeError, lambda x: x + 'hello', x=x) ...
>>> raises(TypeError, "x + 'hello'") >>> raises(ZeroDivisionError, f, 0)
<ExceptionInfo ...>
>>> raises(ZeroDivisionError, f, x=0)
<ExceptionInfo ...>
A third possibility is to use a string which which will
be executed::
>>> raises(ZeroDivisionError, "f(0)")
<ExceptionInfo ...>
""" """
__tracebackhide__ = True __tracebackhide__ = True

View File

@ -24,8 +24,8 @@ def pytest_namespace():
return {'deprecated_call': deprecated_call} return {'deprecated_call': deprecated_call}
def deprecated_call(func, *args, **kwargs): def deprecated_call(func, *args, **kwargs):
""" assert that calling func(*args, **kwargs) """ assert that calling ``func(*args, **kwargs)``
triggers a DeprecationWarning. triggers a DeprecationWarning.
""" """
warningmodule = py.std.warnings warningmodule = py.std.warnings
l = [] l = []

View File

@ -408,7 +408,8 @@ class Session(FSCollector):
path = names.pop(0) path = names.pop(0)
if path.check(dir=1): if path.check(dir=1):
assert not names, "invalid arg %r" %(arg,) assert not names, "invalid arg %r" %(arg,)
for path in path.visit(rec=self._recurse, bf=True, sort=True): for path in path.visit(fil=lambda x: x.check(file=1),
rec=self._recurse, bf=True, sort=True):
for x in self._collectfile(path): for x in self._collectfile(path):
yield x yield x
else: else:
@ -424,12 +425,13 @@ class Session(FSCollector):
return ihook.pytest_collect_file(path=path, parent=self) return ihook.pytest_collect_file(path=path, parent=self)
def _recurse(self, path): def _recurse(self, path):
ihook = self.gethookproxy(path) ihook = self.gethookproxy(path.dirpath())
if ihook.pytest_ignore_collect(path=path, config=self.config): if ihook.pytest_ignore_collect(path=path, config=self.config):
return return
for pat in self._norecursepatterns: for pat in self._norecursepatterns:
if path.check(fnmatch=pat): if path.check(fnmatch=pat):
return False return False
ihook = self.gethookproxy(path)
ihook.pytest_collect_directory(path=path, parent=self) ihook.pytest_collect_directory(path=path, parent=self)
return True return True

View File

@ -87,6 +87,7 @@ and "pytest.raises" used as the recommended default way.
- py.test.config is now only available if you are in a test run. - py.test.config is now only available if you are in a test run.
- the following (mostly already deprecated) functionality was removed: - the following (mostly already deprecated) functionality was removed:
- removed support for Module/Class/... collection node definitions - removed support for Module/Class/... collection node definitions
in conftest.py files. They will cause nothing special. in conftest.py files. They will cause nothing special.
- removed support for calling the pre-1.0 collection API of "run()" and "join" - removed support for calling the pre-1.0 collection API of "run()" and "join"

View File

@ -15,6 +15,7 @@ py.test reference documentation
xunit_setup.txt xunit_setup.txt
capture.txt capture.txt
monkeypatch.txt monkeypatch.txt
xdist.txt
tmpdir.txt tmpdir.txt
skipping.txt skipping.txt
mark.txt mark.txt

View File

@ -1,8 +1,10 @@
.. _`pytest helpers`:
pytest builtin helpers pytest builtin helpers
================================================ ================================================
builtin pytest.* helpers builtin pytest.* functions and helping objects
----------------------------------------------------- -----------------------------------------------------
You can always use an interactive Python prompt and type:: You can always use an interactive Python prompt and type::

View File

View File

@ -1,123 +0,0 @@
Looping on the failing test set
-----------------------------------------
``py.test --looponfailing`` (implemented through the external
`pytest-xdist`_ plugin) allows to run a test suite,
memorize all failures and then loop over the failing set
of tests until they all pass. It will re-start running
the tests when it detects file changes in your project.
select tests by keyword / test name search
-----------------------------------------------------
.. _`selection by keyword`:
You can selectively run tests by specifiying a keyword
on the command line. Examples::
py.test -k test_simple
py.test -k "-test_simple"
will run all tests matching (or not matching) the
"test_simple" keyword. Note that you need to quote
the keyword if "-" is recognized as an indicator
for a commandline option. Lastly, you may use::
py.test. -k "test_simple:"
which will run all tests after the expression has *matched once*, i.e.
all tests that are seen after a test that matches the "test_simple"
keyword.
By default, all filename parts and
class/function names of a test function are put into the set
of keywords for a given test. You can specify additional
kewords like this:
.. sourcecode:: python
@py.test.mark.webtest
def test_send_http():
...
and then use those keywords to select tests. See the `pytest_keyword`_
plugin for more information.
.. _`pytest_keyword`: plugin/mark.html
skip or expect-to-fail a test
-------------------------------------------
py.test has a dedicated `skipping plugin`_ that allows to define
* define "skip" outcomes indicating a platform or a
dependency mismatch.
* "xfail" outcomes indicating an "expected failure" either with
with or without running a test.
* skip and xfail outcomes can be applied at module, class or method
level or even only for certain argument sets of a parametrized function.
.. _`skipping plugin`: plugin/skipping.html
.. _`funcargs mechanism`: funcargs.html
.. _`doctest.py`: http://docs.python.org/library/doctest.html
.. _`xUnit style setup`: xunit_setup.html
.. _`pytest_nose`: plugin/nose.html
no-boilerplate testing
----------------------------------
.. _`autocollect`:
automatic Python test discovery
+++++++++++++++++++++++++++++++++++
By default, all python modules with a ``test_*.py``
filename are inspected for finding tests:
* functions with a name beginning with ``test_``
* classes with a leading ``Test`` name and ``test`` prefixed methods.
* ``unittest.TestCase`` subclasses
parametrizing test functions and functional testing
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
py.test offers the unique `funcargs mechanism`_ for setting up
and passing project-specific objects to Python test functions.
Test Parametrization happens by triggering a call to the same test
function with different argument values. For doing fixtures
using the funcarg mechanism makes your test and setup code
more efficient and more readable. This is especially true
for functional tests which might depend on command line
options and a setup that needs to be shared across
a whole test run.
per-test capturing of output, including subprocesses
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
By default, ``py.test`` captures all writes to stdout/stderr.
Output from ``print`` statements as well as from subprocesses
is captured_. When a test fails, the associated captured outputs are shown.
This allows you to put debugging print statements in your code without
being overwhelmed by all the output that might be generated by tests
that do not fail.
.. _captured: plugin/capture.html
information-rich tracebacks, PDB introspection
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
.. _`example tracebacks`: http://paste.pocoo.org/show/134814/
A lot of care is taken to present useful failure information
and in particular nice and concise Python tracebacks. This
is especially useful if you need to regularly look at failures
from nightly runs, i.e. are detached from the actual test
running session. Here are `example tracebacks`_ for a number of failing
test functions. You can modify traceback printing styles through the
command line. Using the `--pdb`` option you can automatically activate
a PDB `Python debugger`_ when a test fails.

View File

@ -5,12 +5,12 @@ no-boilerplate testing with Python
---------------------------------- ----------------------------------
- automatic, fully customizable Python test discovery - automatic, fully customizable Python test discovery
- allows fully :pep:`8` compliant coding style
- write simple test functions and freely group tests - write simple test functions and freely group tests
- ``assert`` statement for your assertions - ``assert`` statement for your assertions
- powerful parametrization of test functions - powerful parametrization of test functions
- rely on powerful traceback and assertion reporting - rely on helpful traceback and failing assertion reporting
- use ``print`` or ``pdb`` debugging on failures - use ``print`` or ``pdb`` debugging on failures
- enables fully :pep:`8` compliant coding style
extensive plugin and customization system extensive plugin and customization system
------------------------------------------------------ ------------------------------------------------------
@ -25,11 +25,9 @@ extensive plugin and customization system
mature command line testing tool mature command line testing tool
-------------------------------------- --------------------------------------
- powerful :ref:`usage` possibilities - powerful :ref:`usage` possibilities, well sorted command line options
- used in many projects, ranging from 10 to 10K tests - used in many projects, ranging from 10 to 10K tests
- simple well sorted command line options - tested on Unix and Windows from Python 2.4 up to Python 3.1 and 3.2
- runs on Unix, Windows from Python 2.4 up to Python 3.1 and 3.2
- is itself tested extensively on a CI server
- keyword/testname based selection of tests - keyword/testname based selection of tests
integrates well with CI systems integrates well with CI systems
@ -41,7 +39,6 @@ integrates well with CI systems
.. _`tox`: http://codespeak.net/tox .. _`tox`: http://codespeak.net/tox
supports common testing practises and methods supports common testing practises and methods
----------------------------------------------------------- -----------------------------------------------------------

View File

@ -36,17 +36,17 @@ That's it. You can execute the test function now::
=========================== test session starts ============================ =========================== test session starts ============================
platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev30 platform linux2 -- Python 2.6.5 -- pytest-2.0.0.dev30
test path 1: /tmp/doc-exec-70 test path 1: /tmp/doc-exec-70
test_sample.py F test_sample.py F
================================= FAILURES ================================= ================================= FAILURES =================================
_______________________________ test_answer ________________________________ _______________________________ test_answer ________________________________
def test_answer(): def test_answer():
> assert func(3) == 5 > assert func(3) == 5
E assert 4 == 5 E assert 4 == 5
E + where 4 = func(3) E + where 4 = func(3)
test_sample.py:5: AssertionError test_sample.py:5: AssertionError
========================= 1 failed in 0.02 seconds ========================= ========================= 1 failed in 0.02 seconds =========================
@ -120,14 +120,14 @@ run the module by passing its filename::
.F .F
================================= FAILURES ================================= ================================= FAILURES =================================
____________________________ TestClass.test_two ____________________________ ____________________________ TestClass.test_two ____________________________
self = <test_class.TestClass instance at 0x288fc20> self = <test_class.TestClass instance at 0x288fc20>
def test_two(self): def test_two(self):
x = "hello" x = "hello"
> assert hasattr(x, 'check') > assert hasattr(x, 'check')
E assert hasattr('hello', 'check') E assert hasattr('hello', 'check')
test_class.py:8: AssertionError test_class.py:8: AssertionError
1 failed, 1 passed in 0.02 seconds 1 failed, 1 passed in 0.02 seconds
@ -156,14 +156,14 @@ before performing the test function call. Let's just run it::
F F
================================= FAILURES ================================= ================================= FAILURES =================================
_____________________________ test_needsfiles ______________________________ _____________________________ test_needsfiles ______________________________
tmpdir = local('/tmp/pytest-122/test_needsfiles0') tmpdir = local('/tmp/pytest-122/test_needsfiles0')
def test_needsfiles(tmpdir): def test_needsfiles(tmpdir):
print tmpdir print tmpdir
> assert 0 > assert 0
E assert 0 E assert 0
test_tmpdir.py:3: AssertionError test_tmpdir.py:3: AssertionError
----------------------------- Captured stdout ------------------------------ ----------------------------- Captured stdout ------------------------------
/tmp/pytest-122/test_needsfiles0 /tmp/pytest-122/test_needsfiles0
@ -194,29 +194,20 @@ Known Installation issues
easy_install or pip not found? easy_install or pip not found?
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Consult `distribute docs <distribute>`_ to install the ``easy_install`` Consult `distribute docs`_ to install the ``easy_install``
tool on your machine. You may also use the original but somewhat older tool on your machine. You may also use the older
`setuptools`_ project although we generally recommend to use `setuptools`_ project but it lacks bug fixes and does not
``distribute`` because it contains more bug fixes and also works for work on Python3. If you use Python2 you may also install pip_.
Python3.
For Python2 you can also consult pip_ for the popular ``pip`` tool.
However, If you want to install on Python3 you need to use Distribute_ which
provides the ``easy_install`` utility.
py.test not found on Windows despite installation? py.test not found on Windows despite installation?
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.. _`Python for Windows`: http://www.imladris.com/Scripts/PythonForWindows.html .. _`Python for Windows`: http://www.imladris.com/Scripts/PythonForWindows.html
- **Windows**: If "easy_install" or "py.test" are not found - **Windows**: If "easy_install" or "py.test" are not found
please see here for preparing your environment for running you need to add the Python script path to your ``PATH``, see here:
command line tools: `Python for Windows`_. You may alternatively `Python for Windows`_. You may alternatively use an `ActivePython install`_
use an `ActivePython install`_ which makes command line tools which does this for you automatically.
automatically available under Windows.
.. _`ActivePython install`: http://www.activestate.com/activepython/downloads .. _`ActivePython install`: http://www.activestate.com/activepython/downloads

View File

@ -5,8 +5,8 @@ py.test: no-boilerplate testing with Python
.. note:: .. note::
version 2.0 introduces ``pytest`` as the main Python import name version 2.0 introduces ``pytest`` as the main Python import name
but for compatibility reasons you can continue to use ``py.test`` but for compatibility reasons you can continue to use ``import py``
in your test code. and ``py.test.XYZ`` to access :ref:`pytest helpers` in your test code.
Welcome to ``py.test`` documentation: Welcome to ``py.test`` documentation:
@ -25,6 +25,7 @@ Welcome to ``py.test`` documentation:
:hidden: :hidden:
changelog.txt changelog.txt
example/attic
Indices and tables Indices and tables
================== ==================

View File

@ -12,6 +12,7 @@
.. _`setuptools`: http://pypi.python.org/pypi/setuptools .. _`setuptools`: http://pypi.python.org/pypi/setuptools
.. _`easy_install`: .. _`easy_install`:
.. _`distribute docs`:
.. _`distribute`: http://pypi.python.org/pypi/distribute .. _`distribute`: http://pypi.python.org/pypi/distribute
.. _`pip`: http://pypi.python.org/pypi/pip .. _`pip`: http://pypi.python.org/pypi/pip
.. _`virtualenv`: http://pypi.python.org/pypi/virtualenv .. _`virtualenv`: http://pypi.python.org/pypi/virtualenv

View File

@ -4,7 +4,6 @@ Running test written for nose
.. include:: links.inc .. include:: links.inc
py.test has basic support for running tests written for nose_. py.test has basic support for running tests written for nose_.
This is implemented in :pymod:`_pytest.nose`.
Usage Usage
------------- -------------
@ -13,8 +12,8 @@ type::
py.test # instead of 'nosetests' py.test # instead of 'nosetests'
and you should be able to run your nose style tests and at the same and you should be able to run your nose style tests and
make full use of py.test's capabilities. make use of py.test's capabilities.
Supported nose Idioms Supported nose Idioms
---------------------- ----------------------
@ -25,18 +24,12 @@ Supported nose Idioms
* yield-based tests and their setup * yield-based tests and their setup
* general usage of nose utilities * general usage of nose utilities
Unsupported idioms / issues Unsupported idioms / known issues
---------------------------------- ----------------------------------
- nose-style doctests are not collected and executed correctly, - nose-style doctests are not collected and executed correctly,
also fixtures don't work. also doctest fixtures don't work.
- no nose-configuration is recognized - no nose-configuration is recognized
If you find other issues or have suggestions please run::
py.test --pastebin=all
and send the resulting URL to a py.test contact channel,
at best to the mailing list.
"""

View File

@ -52,7 +52,6 @@ earlier than further away ones.
under a package scope or to never import anything from a under a package scope or to never import anything from a
conftest.py file. conftest.py file.
.. _`installing plugins`:
.. _`external plugins`: .. _`external plugins`:
Installing External Plugins / Searching Installing External Plugins / Searching
@ -85,12 +84,11 @@ you can copy from:
* around 20 `builtin plugins`_ which comprise py.test's own functionality * around 20 `builtin plugins`_ which comprise py.test's own functionality
* around 10 `external plugins`_ providing additional features * around 10 `external plugins`_ providing additional features
All of these plugins are using the documented `well specified hooks`_ All of these plugins implement the documented `well specified hooks`_
to implement their wide-ranging functionality. to extend and add functionality.
.. _`setuptools entry points`: .. _`setuptools entry points`:
Making your plugin installable by others Making your plugin installable by others
----------------------------------------------- -----------------------------------------------

View File

@ -39,7 +39,7 @@ class TestGeneralUsage:
def test_1(pytestconfig): def test_1(pytestconfig):
pytestconfig.getbasetemp().ensure("hello") pytestconfig.getbasetemp().ensure("hello")
""") """)
result = testdir.runpytest(p, '--basetemp=%s' %mytemp) result = testdir.runpytest(p, '--basetemp=%s' % mytemp)
assert result.ret == 0 assert result.ret == 0
assert mytemp.join('hello').check() assert mytemp.join('hello').check()
@ -239,7 +239,7 @@ class TestInvocationVariants:
def test_pydoc(self, testdir): def test_pydoc(self, testdir):
for name in ('py.test', 'pytest'): for name in ('py.test', 'pytest'):
result = testdir.runpython_c("import %s;help(%s)" % (name,name)) result = testdir.runpython_c("import %s;help(%s)" % (name, name))
assert result.ret == 0 assert result.ret == 0
s = result.stdout.str() s = result.stdout.str()
assert 'MarkGenerator' in s assert 'MarkGenerator' in s
@ -325,7 +325,7 @@ class TestInvocationVariants:
class MyPlugin: class MyPlugin:
def pytest_addoption(self, parser): def pytest_addoption(self, parser):
parser.addoption("--myopt") parser.addoption("--myopt")
pytest.main(["-h"], plugins=[MyPlugin()]) pytest.main(["-h"], plugins=[MyPlugin()])
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert "--myopt" in out assert "--myopt" in out
@ -358,7 +358,6 @@ class TestInvocationVariants:
"ERROR*file*or*package*not*found*", "ERROR*file*or*package*not*found*",
]) ])
@pytest.mark.xfail(reason="decide: feature or bug") @pytest.mark.xfail(reason="decide: feature or bug")
def test_noclass_discovery_if_not_testcase(self, testdir): def test_noclass_discovery_if_not_testcase(self, testdir):
testpath = testdir.makepyfile(""" testpath = testdir.makepyfile("""

View File

@ -204,12 +204,12 @@ class TestCustomConftests:
return path.basename.startswith("x") or \ return path.basename.startswith("x") or \
path.basename == "test_one.py" path.basename == "test_one.py"
""") """)
testdir.mkdir("xy123").ensure("test_hello.py").write( sub = testdir.mkdir("xy123")
"syntax error" sub.ensure("test_hello.py").write("syntax error")
) sub.join("conftest.py").write("syntax error")
testdir.makepyfile("def test_hello(): pass") testdir.makepyfile("def test_hello(): pass")
testdir.makepyfile(test_one="syntax error") testdir.makepyfile(test_one="syntax error")
result = testdir.runpytest() result = testdir.runpytest("--fulltrace")
assert result.ret == 0 assert result.ret == 0
result.stdout.fnmatch_lines(["*1 passed*"]) result.stdout.fnmatch_lines(["*1 passed*"])

View File

@ -2,6 +2,10 @@ import py, pytest
from _pytest.mark import MarkGenerator as Mark from _pytest.mark import MarkGenerator as Mark
class TestMark: class TestMark:
def test_pytest_exists_in_namespace_all(self):
assert 'mark' in py.test.__all__
assert 'mark' in pytest.__all__
def test_pytest_mark_notcallable(self): def test_pytest_mark_notcallable(self):
mark = Mark() mark = Mark()
pytest.raises((AttributeError, TypeError), "mark()") pytest.raises((AttributeError, TypeError), "mark()")

View File

@ -24,6 +24,12 @@ commands=
py.test -n3 -rfsxX \ py.test -n3 -rfsxX \
--junitxml={envlogdir}/junit-{envname}.xml [] --junitxml={envlogdir}/junit-{envname}.xml []
[testenv:doctest]
changedir=.
commands=py.test --doctest-modules _pytest
deps=
[testenv:doc] [testenv:doc]
basepython=python basepython=python
changedir=doc changedir=doc
@ -57,6 +63,6 @@ commands=
[pytest] [pytest]
minversion=2.0 minversion=2.0
plugins=pytester plugins=pytester
addopts= -rxf --pyargs addopts= -rxf --pyargs --doctest-modules
rsyncdirs=tox.ini pytest.py _pytest testing rsyncdirs=tox.ini pytest.py _pytest testing