diff --git a/CHANGELOG b/CHANGELOG index 9ca34b45a..f75588a81 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -29,9 +29,8 @@ Changes between 2.0.1 and 2.0.2 a newer py lib version the py.path.local() implementation acknowledges this. -- fixed typos in the docs (thanks Victor, Brianna) and particular - thanks to Laura who also revieved the documentation which - lead to some improvements. +- fixed typos in the docs (thanks Victor Garcia, Brianna Laugher) and particular + thanks to Laura Creighton who also revieved parts of the documentation. Changes between 2.0.0 and 2.0.1 ---------------------------------------------- diff --git a/_pytest/capture.py b/_pytest/capture.py index 2da398383..b7594be31 100644 --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -192,18 +192,16 @@ class CaptureManager: return rep def pytest_funcarg__capsys(request): - """captures writes to sys.stdout/sys.stderr and makes - them available successively via a ``capsys.readouterr()`` method - which returns a ``(out, err)`` tuple of captured snapshot strings. + """enables capturing of writes to sys.stdout/sys.stderr and makes + captured output available via ``capsys.readouterr()`` method calls + which return a ``(out, err)`` tuple. """ return CaptureFuncarg(py.io.StdCapture) def pytest_funcarg__capfd(request): - """captures writes to file descriptors 1 and 2 and makes - snapshotted ``(out, err)`` string tuples available - via the ``capsys.readouterr()`` method. If the underlying - platform does not have ``os.dup`` (e.g. Jython) tests using - this funcarg will automatically skip. + """enables capturing of writes to file descriptors 1 and 2 and makes + captured output available via ``capsys.readouterr()`` method calls + which return a ``(out, err)`` tuple. """ if not hasattr(os, 'dup'): py.test.skip("capfd funcarg needs os.dup") diff --git a/_pytest/monkeypatch.py b/_pytest/monkeypatch.py index 1ab0b382f..0a530b717 100644 --- a/_pytest/monkeypatch.py +++ b/_pytest/monkeypatch.py @@ -14,8 +14,8 @@ def pytest_funcarg__monkeypatch(request): monkeypatch.delenv(name, value, raising=True) monkeypatch.syspath_prepend(path) - All modifications will be undone when the requesting - test function finished its execution. The ``raising`` + All modifications will be undone after the requesting + test function has finished. The ``raising`` parameter determines if a KeyError or AttributeError will be raised if the set/deletion operation has no target. """ diff --git a/_pytest/recwarn.py b/_pytest/recwarn.py index e2fb2b17e..5e5a92aa6 100644 --- a/_pytest/recwarn.py +++ b/_pytest/recwarn.py @@ -8,6 +8,9 @@ def pytest_funcarg__recwarn(request): * ``pop(category=None)``: return last warning matching the category. * ``clear()``: clear list of warnings + + See http://docs.python.org/library/warnings.html for information + on warning categories. """ if sys.version_info >= (2,7): import warnings diff --git a/_pytest/tmpdir.py b/_pytest/tmpdir.py index 9eab52d54..2fd9992cc 100644 --- a/_pytest/tmpdir.py +++ b/_pytest/tmpdir.py @@ -59,7 +59,7 @@ def pytest_unconfigure(config): def pytest_funcarg__tmpdir(request): """return a temporary directory path object - unique to each test function invocation, + which is unique to each test function invocation, created as a sub directory of the base temporary directory. The returned object is a `py.path.local`_ path object. diff --git a/doc/assert.txt b/doc/assert.txt index d487fd3ba..f60e0684a 100644 --- a/doc/assert.txt +++ b/doc/assert.txt @@ -1,15 +1,15 @@ -Writing and reporting of assertions in tests -============================================ +The writing and reporting of assertions in tests +================================================== .. _`assert with the assert statement`: assert with the ``assert`` statement --------------------------------------------------------- -``py.test`` allows to use the standard python ``assert`` for verifying +``py.test`` allows you to use the standard python ``assert`` for verifying expectations and values in Python tests. For example, you can write the -following in your tests:: +following:: # content of test_assert1.py def f(): @@ -18,12 +18,12 @@ following in your tests:: def test_function(): assert f() == 4 -to state that your object has a certain ``attribute``. In case this +to assert that your object returns a certain value. If this assertion fails you will see the value of ``x``:: $ py.test test_assert1.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_assert1.py F @@ -37,30 +37,33 @@ assertion fails you will see the value of ``x``:: E + where 3 = f() test_assert1.py:5: AssertionError - ========================= 1 failed in 0.02 seconds ========================= + ========================= 1 failed in 0.03 seconds ========================= Reporting details about the failing assertion is achieved by re-evaluating -the assert expression and recording intermediate values. +the assert expression and recording the intermediate values. Note: If evaluating the assert expression has side effects you may get a warning that the intermediate values could not be determined safely. A -common example for this issue is reading from a file and comparing in one -line:: +common example of this issue is an assertion which reads from a file:: assert f.read() != '...' -This might fail but when re-interpretation comes along it might pass. You can -rewrite this (and any other expression with side effects) easily, though:: +If this assertion fails then the re-evaluation will probably succeed! +This is because ``f.read()`` will return an empty string when it is +called the second time during the re-evaluation. However, it is +easy to rewrite the assertion and avoid any trouble:: content = f.read() assert content != '...' + assertions about expected exceptions ------------------------------------------ In order to write assertions about raised exceptions, you can use ``pytest.raises`` as a context manager like this:: + import pytest with pytest.raises(ZeroDivisionError): 1 / 0 @@ -105,7 +108,7 @@ if you run this module:: $ py.test test_assert2.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_assert2.py F diff --git a/doc/builtin.txt b/doc/builtin.txt index 2e5277ee5..caefba695 100644 --- a/doc/builtin.txt +++ b/doc/builtin.txt @@ -12,7 +12,7 @@ You can always use an interactive Python prompt and type:: import pytest help(pytest) -to get an overview on available globally available helpers. +to get an overview on the globally available helpers. .. automodule:: pytest :members: @@ -27,20 +27,18 @@ You can ask for available builtin or project-custom pytestconfig the pytest config object with access to command line opts. capsys - captures writes to sys.stdout/sys.stderr and makes - them available successively via a ``capsys.readouterr()`` method - which returns a ``(out, err)`` tuple of captured snapshot strings. + enables capturing of writes to sys.stdout/sys.stderr and makes + captured output available via ``capsys.readouterr()`` method calls + which return a ``(out, err)`` tuple. capfd - captures writes to file descriptors 1 and 2 and makes - snapshotted ``(out, err)`` string tuples available - via the ``capsys.readouterr()`` method. If the underlying - platform does not have ``os.dup`` (e.g. Jython) tests using - this funcarg will automatically skip. + enables capturing of writes to file descriptors 1 and 2 and makes + captured output available via ``capsys.readouterr()`` method calls + which return a ``(out, err)`` tuple. tmpdir return a temporary directory path object - unique to each test function invocation, + which is unique to each test function invocation, created as a sub directory of the base temporary directory. The returned object is a `py.path.local`_ path object. @@ -57,8 +55,8 @@ You can ask for available builtin or project-custom monkeypatch.delenv(name, value, raising=True) monkeypatch.syspath_prepend(path) - All modifications will be undone when the requesting - test function finished its execution. The ``raising`` + All modifications will be undone after the requesting + test function has finished. The ``raising`` parameter determines if a KeyError or AttributeError will be raised if the set/deletion operation has no target. @@ -68,3 +66,6 @@ You can ask for available builtin or project-custom * ``pop(category=None)``: return last warning matching the category. * ``clear()``: clear list of warnings + See http://docs.python.org/library/warnings.html for information + on warning categories. + diff --git a/doc/capture.txt b/doc/capture.txt index 1d70271a1..1434e6f9a 100644 --- a/doc/capture.txt +++ b/doc/capture.txt @@ -1,16 +1,44 @@ .. _`captures`: -Capturing of stdout/stderr output +Capturing of the stdout/stderr output ========================================================= -By default ``stdout`` and ``stderr`` output is captured separately for -setup and test execution code. If a test or a setup method fails its -according output will usually be shown along with the failure traceback. -In addition, ``stdin`` is set to a "null" object which will fail all -attempts to read from it. This is important if some code paths in -test otherwise might lead to waiting for input - which is usually -not desired when running automated tests. +Default stdout/stderr/stdin capturing behaviour +--------------------------------------------------------- + +During test execution any output sent to ``stdout`` and ``stderr`` is +captured. If a test or a setup method fails its according captured +output will usually be shown along with the failure traceback. + +In addition, ``stdin`` is set to a "null" object which will +fail on attempts to read from it because it is rarely desired +to wait for interactive input when running automated tests. + +By default capturing is done by intercepting writes to low level +file descriptors. This allows to capture output from simple +print statements as well as output from a subprocess started by +a test. + +Setting capturing methods or disabling capturing +------------------------------------------------- + +There are two ways in which ``py.test`` can perform capturing: + +* file descriptor (FD) level capturing (default): All writes going to the + operating system file descriptors 1 and 2 will be captured. + +* ``sys`` level capturing: Only writes to Python files ``sys.stdout`` + and ``sys.stderr`` will be captured. No capturing of writes to + filedescriptors is performed. + +.. _`disable capturing`: + +You can influence output capturing mechanisms from the command line:: + + py.test -s # disable all capturing + py.test --capture=sys # replace sys.stdout/stderr with in-mem files + py.test --capture=fd # also point filedescriptors 1 and 2 to temp file .. _printdebugging: @@ -36,7 +64,7 @@ of the failing function and hide the other one:: $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 2 items test_module.py .F @@ -50,33 +78,9 @@ of the failing function and hide the other one:: test_module.py:9: AssertionError ----------------------------- Captured stdout ------------------------------ - setting up + setting up ==================== 1 failed, 1 passed in 0.02 seconds ==================== -Setting capturing methods or disabling capturing -------------------------------------------------- - -There are two ways in which ``py.test`` can perform capturing: - -* ``fd`` level capturing (default): All writes going to the operating - system file descriptors 1 and 2 will be captured, for example writes such - as ``os.write(1, 'hello')``. Capturing on ``fd``-level also includes - **output from subprocesses**. - -* ``sys`` level capturing: The ``sys.stdout`` and ``sys.stderr`` will - will be replaced with in-memory files and the ``print`` builtin or - output from code like ``sys.stderr.write(...)`` will be captured with - this method. - -.. _`disable capturing`: - -You can influence output capturing mechanisms from the command line:: - - py.test -s # disable all capturing - py.test --capture=sys # replace sys.stdout/stderr with in-mem files - py.test --capture=fd # also point filedescriptors 1 and 2 to temp file - - Accessing captured output from a test function --------------------------------------------------- diff --git a/doc/customize.txt b/doc/customize.txt index 6049dfeb3..cc1b1e2be 100644 --- a/doc/customize.txt +++ b/doc/customize.txt @@ -4,20 +4,20 @@ basic test configuration Command line options and configuration file settings ----------------------------------------------------------------- -You can get help on options and ini-config values by running:: +You can get help on command line options and values in INI-style +configurations files by using the general help option:: py.test -h # prints options _and_ config file settings This will display command line and configuration file settings which were registered by installed plugins. +How test configuration is read from configuration INI-files +------------------------------------------------------------- -how test configuration is read from setup/tox ini-files --------------------------------------------------------- - -py.test searched for the first matching ini-style configuration file +py.test searches for the first matching ini-style configuration file in the directories of command line argument and the directories above. -It looks for filenames in this order:: +It looks for file basenames in this order:: pytest.ini tox.ini @@ -44,29 +44,27 @@ is used to start the search. .. _`how to change command line options defaults`: .. _`adding default options`: -how to change command line options defaults +How to change command line options defaults ------------------------------------------------ -py.test provides a simple way to set some default -command line options. For example, if you want -to always see detailed info on skipped and xfailed -tests, as well as have terser "dot progress output", -you can add this to your root directory:: +It can be tedious to type the same series of command line options +every time you use py.test . For example, if you always want to see +detailed info on skipped and xfailed tests, as well as have terser "dot" +progress output, you can write it into a configuration file:: # content of pytest.ini # (or tox.ini or setup.cfg) [pytest] addopts = -rsxX -q -From now on, running ``py.test`` will implicitly add -the specified options. +From now on, running ``py.test`` will add the specified options. builtin configuration file options ---------------------------------------------- .. confval:: minversion - specifies a minimal pytest version needed for running tests. + specifies a minimal pytest version required for running tests. minversion = 2.1 # will fail if we run with pytest-2.0 @@ -97,14 +95,14 @@ builtin configuration file options [!seq] matches any char not in seq Default patterns are ``.* _* CVS {args}``. Setting a ``norecurse`` - replaces the default. Here is a customizing example for avoiding - a different set of directories:: + replaces the default. Here is an example of how to avoid + certain directories:: # content of setup.cfg [pytest] norecursedirs = .svn _build tmp* - This would tell py.test to not recurse into typical subversion or + This would tell py.test to not look into typical subversion or sphinx-build directories or into any ``tmp`` prefixed directory. .. confval:: python_files diff --git a/doc/develop.txt b/doc/develop.txt index 60447309f..96b7eb0b1 100644 --- a/doc/develop.txt +++ b/doc/develop.txt @@ -22,7 +22,7 @@ download and unpack a TAR file:: http://pypi.python.org/pypi/pytest/ -activating a checkout with setuptools +Activating a checkout with setuptools -------------------------------------------- With a working Distribute_ or setuptools_ installation you can type:: diff --git a/doc/doctest.txt b/doc/doctest.txt index c9518cc8f..3db3430d7 100644 --- a/doc/doctest.txt +++ b/doc/doctest.txt @@ -1,5 +1,5 @@ -doctest integration for modules and test files. +doctest integration for modules and test files ========================================================= By default all files matching the ``test*.txt`` pattern will @@ -44,7 +44,7 @@ then you can just invoke ``py.test`` without command line options:: $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items mymodule.py . diff --git a/doc/example/mysetup.txt b/doc/example/mysetup.txt index 6e8b9906e..460d4018c 100644 --- a/doc/example/mysetup.txt +++ b/doc/example/mysetup.txt @@ -26,7 +26,7 @@ Let's write a simple test function using a ``mysetup`` funcarg:: To run this test py.test needs to find and call a factory to obtain the required ``mysetup`` function argument. To make an according factory findable we write down a specifically named factory -method in a :ref:`local plugin`:: +method in a :ref:`local plugin ` :: # content of conftest.py from myapp import MyApp @@ -49,7 +49,7 @@ You can now run the test:: $ py.test test_sample.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_sample.py F @@ -57,7 +57,7 @@ You can now run the test:: ================================= FAILURES ================================= _______________________________ test_answer ________________________________ - mysetup = + mysetup = def test_answer(mysetup): app = mysetup.myapp() @@ -122,12 +122,12 @@ Running it yields:: $ py.test test_ssh.py -rs =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_ssh.py s ========================= short test summary info ========================== - SKIP [1] /tmp/doc-exec-166/conftest.py:22: specify ssh host with --ssh + SKIP [1] /tmp/doc-exec-35/conftest.py:22: specify ssh host with --ssh ======================== 1 skipped in 0.02 seconds ========================= diff --git a/doc/example/nonpython.txt b/doc/example/nonpython.txt index 34cb47b2e..ae304bb8a 100644 --- a/doc/example/nonpython.txt +++ b/doc/example/nonpython.txt @@ -27,7 +27,7 @@ now execute the test specification:: nonpython $ py.test test_simple.yml =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 2 items test_simple.yml .F @@ -37,7 +37,7 @@ now execute the test specification:: usecase execution failed spec failed: 'some': 'other' no further details known at this point. - ==================== 1 failed, 1 passed in 0.06 seconds ==================== + ==================== 1 failed, 1 passed in 0.36 seconds ==================== You get one dot for the passing ``sub1: sub1`` check and one failure. Obviously in the above ``conftest.py`` you'll want to implement a more @@ -56,7 +56,7 @@ reporting in ``verbose`` mode:: nonpython $ py.test -v =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 -- /home/hpk/venv/0/bin/python + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 -- /home/hpk/venv/0/bin/python collecting ... collected 2 items test_simple.yml:1: usecase: ok PASSED @@ -67,7 +67,7 @@ reporting in ``verbose`` mode:: usecase execution failed spec failed: 'some': 'other' no further details known at this point. - ==================== 1 failed, 1 passed in 0.06 seconds ==================== + ==================== 1 failed, 1 passed in 0.08 seconds ==================== While developing your custom test collection and execution it's also interesting to just look at the collection tree:: diff --git a/doc/example/parametrize.txt b/doc/example/parametrize.txt index 1552acea7..f28996bbd 100644 --- a/doc/example/parametrize.txt +++ b/doc/example/parametrize.txt @@ -125,7 +125,7 @@ And then when we run the test:: ================================= FAILURES ================================= __________________________ test_db_initialized[1] __________________________ - db = + db = def test_db_initialized(db): # a dummy test @@ -179,7 +179,7 @@ the respective settings:: ================================= FAILURES ================================= __________________________ test_db_initialized[1] __________________________ - db = + db = def test_db_initialized(db): # a dummy test @@ -190,7 +190,7 @@ the respective settings:: test_backends.py:6: Failed _________________________ TestClass.test_equals[0] _________________________ - self = , a = 1, b = 2 + self = , a = 1, b = 2 def test_equals(self, a, b): > assert a == b @@ -199,7 +199,7 @@ the respective settings:: test_parametrize.py:17: AssertionError ______________________ TestClass.test_zerodivision[1] ______________________ - self = , a = 3, b = 2 + self = , a = 3, b = 2 def test_zerodivision(self, a, b): > pytest.raises(ZeroDivisionError, "a/b") @@ -247,7 +247,7 @@ Running it gives similar results as before:: ================================= FAILURES ================================= _________________________ TestClass.test_equals[0] _________________________ - self = , a = 1, b = 2 + self = , a = 1, b = 2 @params([dict(a=1, b=2), dict(a=3, b=3), ]) def test_equals(self, a, b): @@ -257,7 +257,7 @@ Running it gives similar results as before:: test_parametrize2.py:19: AssertionError ______________________ TestClass.test_zerodivision[1] ______________________ - self = , a = 3, b = 2 + self = , a = 3, b = 2 @params([dict(a=1, b=0), dict(a=3, b=2)]) def test_zerodivision(self, a, b): @@ -286,4 +286,4 @@ Running it (with Python-2.4 through to Python2.7 installed):: . $ py.test -q multipython.py collecting ... collected 75 items ....s....s....s....ssssss....s....s....s....ssssss....s....s....s....ssssss - 48 passed, 27 skipped in 1.59 seconds + 48 passed, 27 skipped in 1.92 seconds diff --git a/doc/example/reportingdemo.txt b/doc/example/reportingdemo.txt index b1e2a2bdf..ffdb34dcc 100644 --- a/doc/example/reportingdemo.txt +++ b/doc/example/reportingdemo.txt @@ -13,7 +13,7 @@ get on the terminal - we are working on that): assertion $ py.test failure_demo.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 39 items failure_demo.py FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF @@ -30,7 +30,7 @@ get on the terminal - we are working on that): failure_demo.py:15: AssertionError _________________________ TestFailing.test_simple __________________________ - self = + self = def test_simple(self): def f(): @@ -40,13 +40,13 @@ get on the terminal - we are working on that): > assert f() == g() E assert 42 == 43 - E + where 42 = () - E + and 43 = () + E + where 42 = () + E + and 43 = () failure_demo.py:28: AssertionError ____________________ TestFailing.test_simple_multiline _____________________ - self = + self = def test_simple_multiline(self): otherfunc_multi( @@ -66,19 +66,19 @@ get on the terminal - we are working on that): failure_demo.py:12: AssertionError ___________________________ TestFailing.test_not ___________________________ - self = + self = def test_not(self): def f(): return 42 > assert not f() E assert not 42 - E + where 42 = () + E + where 42 = () failure_demo.py:38: AssertionError _________________ TestSpecialisedExplanations.test_eq_text _________________ - self = + self = def test_eq_text(self): > assert 'spam' == 'eggs' @@ -89,7 +89,7 @@ get on the terminal - we are working on that): failure_demo.py:42: AssertionError _____________ TestSpecialisedExplanations.test_eq_similar_text _____________ - self = + self = def test_eq_similar_text(self): > assert 'foo 1 bar' == 'foo 2 bar' @@ -102,7 +102,7 @@ get on the terminal - we are working on that): failure_demo.py:45: AssertionError ____________ TestSpecialisedExplanations.test_eq_multiline_text ____________ - self = + self = def test_eq_multiline_text(self): > assert 'foo\nspam\nbar' == 'foo\neggs\nbar' @@ -115,7 +115,7 @@ get on the terminal - we are working on that): failure_demo.py:48: AssertionError ______________ TestSpecialisedExplanations.test_eq_long_text _______________ - self = + self = def test_eq_long_text(self): a = '1'*100 + 'a' + '2'*100 @@ -132,7 +132,7 @@ get on the terminal - we are working on that): failure_demo.py:53: AssertionError _________ TestSpecialisedExplanations.test_eq_long_text_multiline __________ - self = + self = def test_eq_long_text_multiline(self): a = '1\n'*100 + 'a' + '2\n'*100 @@ -156,7 +156,7 @@ get on the terminal - we are working on that): failure_demo.py:58: AssertionError _________________ TestSpecialisedExplanations.test_eq_list _________________ - self = + self = def test_eq_list(self): > assert [0, 1, 2] == [0, 1, 3] @@ -166,7 +166,7 @@ get on the terminal - we are working on that): failure_demo.py:61: AssertionError ______________ TestSpecialisedExplanations.test_eq_list_long _______________ - self = + self = def test_eq_list_long(self): a = [0]*100 + [1] + [3]*100 @@ -178,7 +178,7 @@ get on the terminal - we are working on that): failure_demo.py:66: AssertionError _________________ TestSpecialisedExplanations.test_eq_dict _________________ - self = + self = def test_eq_dict(self): > assert {'a': 0, 'b': 1} == {'a': 0, 'b': 2} @@ -191,7 +191,7 @@ get on the terminal - we are working on that): failure_demo.py:69: AssertionError _________________ TestSpecialisedExplanations.test_eq_set __________________ - self = + self = def test_eq_set(self): > assert set([0, 10, 11, 12]) == set([0, 20, 21]) @@ -207,7 +207,7 @@ get on the terminal - we are working on that): failure_demo.py:72: AssertionError _____________ TestSpecialisedExplanations.test_eq_longer_list ______________ - self = + self = def test_eq_longer_list(self): > assert [1,2] == [1,2,3] @@ -217,7 +217,7 @@ get on the terminal - we are working on that): failure_demo.py:75: AssertionError _________________ TestSpecialisedExplanations.test_in_list _________________ - self = + self = def test_in_list(self): > assert 1 in [0, 2, 3, 4, 5] @@ -226,7 +226,7 @@ get on the terminal - we are working on that): failure_demo.py:78: AssertionError __________ TestSpecialisedExplanations.test_not_in_text_multiline __________ - self = + self = def test_not_in_text_multiline(self): text = 'some multiline\ntext\nwhich\nincludes foo\nand a\ntail' @@ -244,7 +244,7 @@ get on the terminal - we are working on that): failure_demo.py:82: AssertionError ___________ TestSpecialisedExplanations.test_not_in_text_single ____________ - self = + self = def test_not_in_text_single(self): text = 'single foo line' @@ -257,7 +257,7 @@ get on the terminal - we are working on that): failure_demo.py:86: AssertionError _________ TestSpecialisedExplanations.test_not_in_text_single_long _________ - self = + self = def test_not_in_text_single_long(self): text = 'head ' * 50 + 'foo ' + 'tail ' * 20 @@ -270,7 +270,7 @@ get on the terminal - we are working on that): failure_demo.py:90: AssertionError ______ TestSpecialisedExplanations.test_not_in_text_single_long_term _______ - self = + self = def test_not_in_text_single_long_term(self): text = 'head ' * 50 + 'f'*70 + 'tail ' * 20 @@ -289,7 +289,7 @@ get on the terminal - we are working on that): i = Foo() > assert i.b == 2 E assert 1 == 2 - E + where 1 = .b + E + where 1 = .b failure_demo.py:101: AssertionError _________________________ test_attribute_instance __________________________ @@ -299,8 +299,8 @@ get on the terminal - we are working on that): b = 1 > assert Foo().b == 2 E assert 1 == 2 - E + where 1 = .b - E + where = () + E + where 1 = .b + E + where = () failure_demo.py:107: AssertionError __________________________ test_attribute_failure __________________________ @@ -316,7 +316,7 @@ get on the terminal - we are working on that): failure_demo.py:116: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - self = + self = def _get_b(self): > raise Exception('Failed to get attrib') @@ -332,15 +332,15 @@ get on the terminal - we are working on that): b = 2 > assert Foo().b == Bar().b E assert 1 == 2 - E + where 1 = .b - E + where = () - E + and 2 = .b - E + where = () + E + where 1 = .b + E + where = () + E + and 2 = .b + E + where = () failure_demo.py:124: AssertionError __________________________ TestRaises.test_raises __________________________ - self = + self = def test_raises(self): s = 'qwe' @@ -352,10 +352,10 @@ get on the terminal - we are working on that): > int(s) E ValueError: invalid literal for int() with base 10: 'qwe' - <0-codegen /home/hpk/p/pytest/_pytest/python.py:822>:1: ValueError + <0-codegen /home/hpk/p/pytest/_pytest/python.py:825>:1: ValueError ______________________ TestRaises.test_raises_doesnt _______________________ - self = + self = def test_raises_doesnt(self): > raises(IOError, "int('3')") @@ -364,7 +364,7 @@ get on the terminal - we are working on that): failure_demo.py:136: Failed __________________________ TestRaises.test_raise ___________________________ - self = + self = def test_raise(self): > raise ValueError("demo error") @@ -373,7 +373,7 @@ get on the terminal - we are working on that): failure_demo.py:139: ValueError ________________________ TestRaises.test_tupleerror ________________________ - self = + self = def test_tupleerror(self): > a,b = [1] @@ -382,7 +382,7 @@ get on the terminal - we are working on that): failure_demo.py:142: ValueError ______ TestRaises.test_reinterpret_fails_with_print_for_the_fun_of_it ______ - self = + self = def test_reinterpret_fails_with_print_for_the_fun_of_it(self): l = [1,2,3] @@ -395,7 +395,7 @@ get on the terminal - we are working on that): l is [1, 2, 3] ________________________ TestRaises.test_some_error ________________________ - self = + self = def test_some_error(self): > if namenotexi: @@ -423,7 +423,7 @@ get on the terminal - we are working on that): <2-codegen 'abc-123' /home/hpk/p/pytest/doc/example/assertion/failure_demo.py:162>:2: AssertionError ____________________ TestMoreErrors.test_complex_error _____________________ - self = + self = def test_complex_error(self): def f(): @@ -452,7 +452,7 @@ get on the terminal - we are working on that): failure_demo.py:5: AssertionError ___________________ TestMoreErrors.test_z1_unpack_error ____________________ - self = + self = def test_z1_unpack_error(self): l = [] @@ -462,7 +462,7 @@ get on the terminal - we are working on that): failure_demo.py:179: ValueError ____________________ TestMoreErrors.test_z2_type_error _____________________ - self = + self = def test_z2_type_error(self): l = 3 @@ -472,20 +472,20 @@ get on the terminal - we are working on that): failure_demo.py:183: TypeError ______________________ TestMoreErrors.test_startswith ______________________ - self = + self = def test_startswith(self): s = "123" g = "456" > assert s.startswith(g) E assert False - E + where False = ('456') - E + where = '123'.startswith + E + where False = ('456') + E + where = '123'.startswith failure_demo.py:188: AssertionError __________________ TestMoreErrors.test_startswith_nested ___________________ - self = + self = def test_startswith_nested(self): def f(): @@ -494,15 +494,15 @@ get on the terminal - we are working on that): return "456" > assert f().startswith(g()) E assert False - E + where False = ('456') - E + where = '123'.startswith - E + where '123' = () - E + and '456' = () + E + where False = ('456') + E + where = '123'.startswith + E + where '123' = () + E + and '456' = () failure_demo.py:195: AssertionError _____________________ TestMoreErrors.test_global_func ______________________ - self = + self = def test_global_func(self): > assert isinstance(globf(42), float) @@ -513,19 +513,19 @@ get on the terminal - we are working on that): failure_demo.py:198: AssertionError _______________________ TestMoreErrors.test_instance _______________________ - self = + self = def test_instance(self): self.x = 6*7 > assert self.x != 42 E assert 42 != 42 E + where 42 = 42 - E + where 42 = .x + E + where 42 = .x failure_demo.py:202: AssertionError _______________________ TestMoreErrors.test_compare ________________________ - self = + self = def test_compare(self): > assert globf(10) < 5 @@ -535,7 +535,7 @@ get on the terminal - we are working on that): failure_demo.py:205: AssertionError _____________________ TestMoreErrors.test_try_finally ______________________ - self = + self = def test_try_finally(self): x = 1 @@ -544,4 +544,4 @@ get on the terminal - we are working on that): E assert 1 == 0 failure_demo.py:210: AssertionError - ======================== 39 failed in 0.22 seconds ========================= + ======================== 39 failed in 0.26 seconds ========================= diff --git a/doc/example/simple.txt b/doc/example/simple.txt index 5b5db1db3..4efb3795f 100644 --- a/doc/example/simple.txt +++ b/doc/example/simple.txt @@ -109,13 +109,13 @@ directory with the above conftest.py:: $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev0 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 gw0 I / gw1 I / gw2 I / gw3 I gw0 [0] / gw1 [0] / gw2 [0] / gw3 [0] scheduling tests via LoadScheduling - ============================= in 0.37 seconds ============================= + ============================= in 0.35 seconds ============================= .. _`excontrolskip`: @@ -156,12 +156,12 @@ and when running it will see a skipped "slow" test:: $ py.test -rs # "-rs" means report details on the little 's' =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev0 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 2 items test_module.py .s ========================= short test summary info ========================== - SKIP [1] /tmp/doc-exec-275/conftest.py:9: need --runslow option to run + SKIP [1] /tmp/doc-exec-40/conftest.py:9: need --runslow option to run =================== 1 passed, 1 skipped in 0.02 seconds ==================== @@ -169,7 +169,7 @@ Or run it including the ``slow`` marked test:: $ py.test --runslow =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev0 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 2 items test_module.py .. @@ -213,7 +213,7 @@ Let's run our little function:: E Failed: not configured: 42 test_checkconfig.py:8: Failed - 1 failed in 0.02 seconds + 1 failed in 0.03 seconds Detect if running from within a py.test run -------------------------------------------------------------- @@ -261,7 +261,7 @@ which will add the string to the test header accordingly:: $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev0 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 project deps: mylib-1.1 collecting ... collected 0 items @@ -284,7 +284,7 @@ which will add info only when run with "--v":: $ py.test -v =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev0 -- /home/hpk/venv/0/bin/python + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 -- /home/hpk/venv/0/bin/python info1: did you know that ... did you? collecting ... collected 0 items @@ -295,7 +295,7 @@ and nothing when run plainly:: $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev0 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 0 items ============================= in 0.00 seconds ============================= diff --git a/doc/extracol b/doc/extracol deleted file mode 100644 index 7b1f08847..000000000 --- a/doc/extracol +++ /dev/null @@ -1,32 +0,0 @@ -changing Python test discovery patterns --------------------------------------------------- - -You can influence python test file, function and class prefixes through -the :confval:`python_patterns` configuration valueto determine which -files are checked and which test functions are found. Example for using -a scheme that builds on ``check`` rather than on ``test`` prefixes:: - - - # content of setup.cfg - [pytest] - python_patterns = - files: check_*.py - functions: check_ - classes: Check - -See - :confval:`python_funcprefixes` and :confval:`python_classprefixes` - - - changing test file discovery - ----------------------------------------------------- - - You can specify patterns where python tests are found:: - - python_testfilepatterns = - testing/**/{purebasename}.py - testing/*.py - - .. note:: - - conftest.py files are never considered for test discovery diff --git a/doc/faq.txt b/doc/faq.txt index 27048b175..0b76dab26 100644 --- a/doc/faq.txt +++ b/doc/faq.txt @@ -12,25 +12,26 @@ On naming, nosetests, licensing and magic Why a ``py.test`` instead of a ``pytest`` command? ++++++++++++++++++++++++++++++++++++++++++++++++++ -Some historic, some practical reasons: ``py.test`` used to be part of -the ``py`` package which provided several developer utilities, -all starting with ``py.``, providing nice TAB-completion. If +Some of the reasons are historic, others are practical. ``py.test`` +used to be part of the ``py`` package which provided several developer +utilities, all starting with ``py.``, thus providing nice +TAB-completion. If you install ``pip install pycmd`` you get these tools from a separate package. These days the command line tool could be called ``pytest`` -but then again many people have gotten used to the old name and there -is another tool named "pytest" so we just decided to stick with +since many people have gotten used to the old name and there +is another tool named "pytest" we just decided to stick with ``py.test``. -What's the relation to nose and unittest? +How does py.test relate to nose and unittest? +++++++++++++++++++++++++++++++++++++++++++++++++ py.test and nose_ share basic philosophy when it comes -to running Python tests. In fact, you can run many tests -written nose with py.test. nose_ was originally created +to running and writing Python tests. In fact, you can run many tests +written for nose with py.test. nose_ was originally created as a clone of ``py.test`` when py.test was in the ``0.8`` release -cycle. As of version 2.0 support for running unittest test -suites is majorly improved and you should be able to run -many Django and Twisted test suites. +cycle. Note that starting with pytest-2.0 support for running unittest +test suites is majorly improved and you should be able to run +many Django and Twisted test suites without modification. .. _features: test/features.html @@ -39,22 +40,20 @@ What's this "magic" with py.test? ++++++++++++++++++++++++++++++++++++++++++ Around 2007 (version ``0.8``) some people claimed that py.test -was using too much "magic". It has been refactored a lot. Thrown -out old code. Deprecated unused approaches and code. And it is today -probably one of the smallest, most universally runnable and most -customizable testing frameworks for Python. It's true that -``py.test`` uses metaprogramming techniques, i.e. it views -test code similar to how compilers view programs, using a -somewhat abstract internal model. +was using too much "magic". Partly this has been fixed by removing +unused, deprecated or complicated code. It is today probably one +of the smallest, most universally runnable and most +customizable testing frameworks for Python. However, +``py.test`` still uses many metaprogramming techniques and +reading its source is thus likely not something for Python beginners. -It's also true that the no-boilerplate testing is implemented by making -use of the Python assert statement through "re-interpretation": +A second "magic" issue arguably the assert statement re-intepreation: When an ``assert`` statement fails, py.test re-interprets the expression to show intermediate values if a test fails. If your expression -has side effects the intermediate values may not be the same, obfuscating -the initial error (this is also explained at the command line if it happens). +has side effects (better to avoid them anyway!) the intermediate values +may not be the same, obfuscating the initial error (this is also +explained at the command line if it happens). ``py.test --no-assert`` turns off assert re-interpretation. -Sidenote: it is good practise to avoid asserts with side effects. .. _`py namespaces`: index.html .. _`py/__init__.py`: http://bitbucket.org/hpk42/py-trunk/src/trunk/py/__init__.py @@ -69,7 +68,7 @@ Is using funcarg- versus xUnit setup a style question? +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ For simple applications and for people experienced with nose_ or -unittest-style test setup using `xUnit style setup`_ often +unittest-style test setup using `xUnit style setup`_ probably feels natural. For larger test suites, parametrized testing or setup of complex test resources using funcargs_ may feel more natural. Moreover, funcargs are ideal for writing advanced test support @@ -86,13 +85,11 @@ in a managed class/module/function scope. Why the ``pytest_funcarg__*`` name for funcarg factories? ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -We alternatively implemented an explicit registration mechanism for -function argument factories. But lacking a good use case for this -indirection and flexibility we decided to go for `Convention over -Configuration`_ and rather have factories specified by convention. -Besides removing the need for an registration indirection it allows to -"grep" for ``pytest_funcarg__MYARG`` and will safely find all factory -functions for the ``MYARG`` function argument. +We like `Convention over Configuration`_ and didn't see much point +in allowing a more flexible or abstract mechanism. Moreover, +is is nice to be able to search for ``pytest_funcarg__MYARG`` in +a source code and safely find all factory functions for +the ``MYARG`` function argument. .. _`Convention over Configuration`: http://en.wikipedia.org/wiki/Convention_over_Configuration diff --git a/doc/funcargs.txt b/doc/funcargs.txt index f5cee665b..68516f7a7 100644 --- a/doc/funcargs.txt +++ b/doc/funcargs.txt @@ -1,5 +1,5 @@ ============================================================== -creating and managing test function arguments +Injecting objects into test functions (funcargs) ============================================================== .. currentmodule:: _pytest.python @@ -11,16 +11,26 @@ creating and managing test function arguments Dependency injection through function arguments ================================================= -py.test allows to inject values into test functions through the *funcarg -mechanism*: For each argument name in a test function signature a factory is -looked up and called to create the value. The factory can live in the -same test class, test module, in a per-directory ``conftest.py`` file or -in an external plugin. It has full access to the requesting test -function, can register finalizers and invoke lifecycle-caching -helpers. As can be expected from a systematic dependency -injection mechanism, this allows full de-coupling of resource and -fixture setup from test code, enabling more maintainable and -easy-to-modify test suites. +py.test lets you inject objects into test functions and precisely +control their life cycle in relation to the test execution. It is +also possible to run a test function multiple times with different objects. + +The basic mechanism for injecting objects is also called the +*funcarg mechanism* because objects are ultimatly injected +by calling a test function with it as an argument. Unlike the +classical xUnit approach *funcargs* relate more to `Dependency Injection`_ +because they help to de-couple test code from objects required for +them to execute. + +.. _`Dependency injection`: http://en.wikipedia.org/wiki/Dependency_injection + +To create a value with which to call a test function a factory function +is called which gets full access to the test function context and can +register finalizers or invoke lifecycle-caching helpers. The factory +can be implemented in same test class or test module, or in a +per-directory ``conftest.py`` file or even in an external plugin. This +allows full de-coupling of test code and objects needed for test +execution. A test function may be invoked multiple times in which case we speak of :ref:`parametrized testing `. This can be @@ -28,13 +38,13 @@ very useful if you want to test e.g. against different database backends or with multiple numerical arguments sets and want to reuse the same set of test functions. + .. _funcarg: -Basic funcarg example ------------------------ +Basic injection example +-------------------------------- -Let's look at a simple self-contained example that you can put -into a test module:: +Let's look at a simple self-contained test module:: # content of ./test_simplefactory.py def pytest_funcarg__myfuncarg(request): @@ -43,11 +53,15 @@ into a test module:: def test_function(myfuncarg): assert myfuncarg == 17 +This test function needs an injected object named ``myfuncarg``. +py.test will discover and call the factory named +``pytest_funcarg__myfuncarg`` within the same module in this case. + Running the test looks like this:: $ py.test test_simplefactory.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_simplefactory.py F @@ -64,8 +78,8 @@ Running the test looks like this:: test_simplefactory.py:5: AssertionError ========================= 1 failed in 0.02 seconds ========================= -This means that the test function was called with a ``myfuncarg`` value -of ``42`` and the assert fails accordingly. Here is how py.test +This means that indeed the test function was called with a ``myfuncarg`` +argument value of ``42`` and the assert fails. Here is how py.test comes to call the test function this way: 1. py.test :ref:`finds ` the ``test_function`` because @@ -76,14 +90,15 @@ comes to call the test function this way: 2. ``pytest_funcarg__myfuncarg(request)`` is called and returns the value for ``myfuncarg``. -3. the test function can now be called: ``test_function(42)`` - and results in the above exception because of the assertion +3. the test function can now be called: ``test_function(42)``. + This results in the above exception because of the assertion mismatch. Note that if you misspell a function argument or want to use one that isn't available, you'll see an error -with a list of available function arguments. You can -also issue:: +with a list of available function arguments. + +You can always issue:: py.test --funcargs test_simplefactory.py @@ -152,7 +167,7 @@ Running this:: $ py.test test_example.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 10 items test_example.py .........F @@ -167,7 +182,7 @@ Running this:: E assert 9 < 9 test_example.py:7: AssertionError - ==================== 1 failed, 9 passed in 0.03 seconds ==================== + ==================== 1 failed, 9 passed in 0.05 seconds ==================== Note that the ``pytest_generate_tests(metafunc)`` hook is called during the test collection phase which is separate from the actual test running. @@ -190,7 +205,7 @@ If you want to select only the run with the value ``7`` you could do:: $ py.test -v -k 7 test_example.py # or -k test_func[7] =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 -- /home/hpk/venv/0/bin/python + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 -- /home/hpk/venv/0/bin/python collecting ... collected 10 items test_example.py:6: test_func[7] PASSED diff --git a/doc/getting-started.txt b/doc/getting-started.txt index f61de05d6..1e7cb5f57 100644 --- a/doc/getting-started.txt +++ b/doc/getting-started.txt @@ -16,7 +16,7 @@ Installation options:: To check your installation has installed the correct version:: $ py.test --version - This is py.test version 2.0.1, imported from /home/hpk/p/pytest/pytest.py + This is py.test version 2.0.2.dev2, imported from /home/hpk/p/pytest/pytest.py setuptools registered plugins: pytest-xdist-1.6.dev2 at /home/hpk/p/pytest-xdist/xdist/plugin.pyc pytest-pep8-0.7 at /home/hpk/p/pytest-pep8/pytest_pep8.pyc @@ -41,7 +41,7 @@ That's it. You can execute the test function now:: $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_sample.py F @@ -57,7 +57,7 @@ That's it. You can execute the test function now:: test_sample.py:5: AssertionError ========================= 1 failed in 0.02 seconds ========================= -py.test found the ``test_answer`` function by following :ref:`standard test discovery rules `, basically detecting the ``test_`` prefixes. We got a failure report because our little ``func(3)`` call did not return ``5``. The report is formatted using the :ref:`standard traceback reporting`. +py.test found the ``test_answer`` function by following :ref:`standard test discovery rules `, basically detecting the ``test_`` prefixes. We got a failure report because our little ``func(3)`` call did not return ``5``. .. note:: @@ -80,10 +80,10 @@ py.test found the ``test_answer`` function by following :ref:`standard test disc .. _`assert statement`: http://docs.python.org/reference/simple_stmts.html#the-assert-statement -Asserting a certain exception is raised +Asserting that a certain exception is raised -------------------------------------------------------------- -If you want to assert some code raises an exception you can +If you want to assert that some code raises an exception you can use the ``raises`` helper:: # content of test_sysexit.py @@ -107,9 +107,9 @@ Running it with, this time in "quiet" reporting mode:: Grouping multiple tests in a class -------------------------------------------------------------- -If you start to have more than a few tests it often makes sense -to group tests logically, in classes and modules. Let's put two -tests in a class like this:: +Once you start to have more than a few tests it often makes sense +to group tests logically, in classes and modules. Let's write a class +containing two tests:: # content of test_class.py class TestClass: @@ -131,7 +131,7 @@ run the module by passing its filename:: ================================= FAILURES ================================= ____________________________ TestClass.test_two ____________________________ - self = + self = def test_two(self): x = "hello" @@ -140,7 +140,7 @@ run the module by passing its filename:: E + where False = hasattr('hello', 'check') test_class.py:8: AssertionError - 1 failed, 1 passed in 0.02 seconds + 1 failed, 1 passed in 0.04 seconds The first test passed, the second failed. Again we can easily see the intermediate values used in the assertion, helping us to @@ -169,7 +169,7 @@ before performing the test function call. Let's just run it:: ================================= FAILURES ================================= _____________________________ test_needsfiles ______________________________ - tmpdir = local('/tmp/pytest-101/test_needsfiles0') + tmpdir = local('/tmp/pytest-92/test_needsfiles0') def test_needsfiles(tmpdir): print tmpdir @@ -178,8 +178,8 @@ before performing the test function call. Let's just run it:: test_tmpdir.py:3: AssertionError ----------------------------- Captured stdout ------------------------------ - /tmp/pytest-101/test_needsfiles0 - 1 failed in 0.03 seconds + /tmp/pytest-92/test_needsfiles0 + 1 failed in 0.14 seconds Before the test runs, a unique-per-test-invocation temporary directory was created. More info at :ref:`tmpdir handling`. @@ -194,7 +194,7 @@ where to go next Here are a few suggestions where to go next: * :ref:`cmdline` for command line invocation examples -* :ref:`good practises` for virtualenv, test layout, genscript support +* :ref:`good practises ` for virtualenv, test layout, genscript support * :ref:`apiref` for documentation and examples on using py.test * :ref:`plugins` managing and writing plugins @@ -228,7 +228,7 @@ py.test not found on Windows despite installation? - **Jython2.5.1 on Windows XP**: `Jython does not create command line launchers`_ so ``py.test`` will not work correctly. You may install py.test on CPython and type ``py.test --genscript=mytest`` and then use - ``jython mytest`` to run py.test for your tests to run in Jython. + ``jython mytest`` to run py.test for your tests to run with Jython. :ref:`examples` for more complex examples diff --git a/doc/goodpractises.txt b/doc/goodpractises.txt index 59f75f45e..4676c92e7 100644 --- a/doc/goodpractises.txt +++ b/doc/goodpractises.txt @@ -8,14 +8,11 @@ Good Integration Practises Work with virtual environments ----------------------------------------------------------- -We recommend to work with virtualenv_ environments and use easy_install_ +We recommend to use virtualenv_ environments and use easy_install_ (or pip_) for installing your application dependencies as well as -the ``pytest`` package itself. This way you get a much more reproducible +the ``pytest`` package itself. This way you will get a much more reproducible environment. A good tool to help you automate test runs against multiple -dependency configurations or Python interpreters is `tox`_, -independently created by the main py.test author. The latter -is also useful for integration with the continuous integration -server Hudson_. +dependency configurations or Python interpreters is `tox`_. .. _`virtualenv`: http://pypi.python.org/pypi/virtualenv .. _`buildout`: http://www.buildout.org/ @@ -24,10 +21,11 @@ server Hudson_. Use tox and Continuous Integration servers ------------------------------------------------- -If you are (often) releasing code to the public you +If you frequently relase code to the public you may want to look into `tox`_, the virtualenv test automation tool and its `pytest support `_. -The basic idea is to generate a JUnitXML file through the ``--junitxml=PATH`` option and have a continuous integration server like Hudson_ pick it up. +The basic idea is to generate a JUnitXML file through the ``--junitxml=PATH`` option and have a continuous integration server like Jenkins_ pick it up +and generate reports. .. _standalone: .. _`genscript method`: @@ -90,7 +88,7 @@ If you now type:: this will execute your tests using ``runtest.py``. As this is a standalone version of ``py.test`` no prior installation whatsoever is required for calling the test command. You can also pass additional -arguments to the subprocess-calls like your test directory or other +arguments to the subprocess-calls such as your test directory or other options. .. _`test discovery`: @@ -101,14 +99,14 @@ Conventions for Python test discovery ``py.test`` implements the following standard test discovery: -* collection starts from initial command line arguments +* collection starts from the initial command line arguments which may be directories, filenames or test ids. * recurse into directories, unless they match :confval:`norecursedirs` * ``test_*.py`` or ``*_test.py`` files, imported by their `package name`_. * ``Test`` prefixed test classes (without an ``__init__`` method) * ``test_`` prefixed test functions or methods are test items -For changing and customization example, see :doc:`example/pythoncollection`. +For examples of how to cnd cusotmize your test discovery :doc:`example/pythoncollection`. py.test additionally discovers tests using the standard :ref:`unittest.TestCase ` subclassing technique. @@ -154,8 +152,8 @@ You can always run your tests by pointing to it:: Test modules are imported under their fully qualified name as follows: - * find ``basedir`` -- this is the first "upward" directory not - containing an ``__init__.py`` + * find ``basedir`` -- this is the first "upward" (towards the root) + directory not containing an ``__init__.py`` * perform ``sys.path.insert(0, basedir)`` to make the fully qualified test module path importable. diff --git a/doc/index.txt b/doc/index.txt index edd002699..57c0d446b 100644 --- a/doc/index.txt +++ b/doc/index.txt @@ -4,23 +4,25 @@ Welcome to ``py.test``! ============================================= -- **a mature fully featured testing tool** +- **a mature full-featured testing tool** - runs on Posix/Windows, Python 2.4-3.2, PyPy and Jython - continuously `tested on many Python interpreters `_ - - used in :ref:`many projects and organisations `, ranging from 10 to 10000 tests + - used in :ref:`many projects and organisations `, in test + suites ranging from 10 to 10s of thousands of tests - has :ref:`comprehensive documentation ` - comes with :ref:`tested examples ` - supports :ref:`good integration practises ` - **provides no-boilerplate testing** - - makes it :ref:`easy to get started `, refined :ref:`usage options ` + - makes it :ref:`easy to get started `, + - refined :ref:`usage options ` - :ref:`assert with the assert statement` - helpful :ref:`traceback and failing assertion reporting ` - - allows :ref:`print debugging ` and :ref:`generic output - capturing ` - - supports :pep:`8` compliant coding style in tests + - allows :ref:`print debugging ` and :ref:`the + capturing of standard output during test execution ` + - supports :pep:`8` compliant coding styles in tests - **supports functional testing and complex test setups** @@ -39,7 +41,7 @@ Welcome to ``py.test``! tests, including running testcases made for Django and trial - supports extended :ref:`xUnit style setup ` - supports domain-specific :ref:`non-python tests` - - supports generating testing coverage reports + - supports the generation of testing coverage reports - `Javascript unit- and functional testing`_ - **extensive plugin and customization system** diff --git a/doc/links.inc b/doc/links.inc index 34a4114ab..e627f780d 100644 --- a/doc/links.inc +++ b/doc/links.inc @@ -16,4 +16,5 @@ .. _`pip`: http://pypi.python.org/pypi/pip .. _`virtualenv`: http://pypi.python.org/pypi/virtualenv .. _hudson: http://hudson-ci.org/ +.. _jenkins: http://jenkins-ci.org/ .. _tox: http://codespeak.net/tox diff --git a/doc/mark.txt b/doc/mark.txt index d4a0c4d87..bf8707c15 100644 --- a/doc/mark.txt +++ b/doc/mark.txt @@ -7,12 +7,12 @@ mark test functions with attributes .. currentmodule:: _pytest.mark By using the ``pytest.mark`` helper you can instantiate -decorators that will set named meta data on test functions. +decorators that will set named metadata on test functions. Marking a single function ---------------------------------------------------- -You can "mark" a test function with meta data like this:: +You can "mark" a test function with metadata like this:: import pytest @pytest.mark.webtest @@ -20,7 +20,7 @@ You can "mark" a test function with meta data like this:: ... This will set the function attribute ``webtest`` to a :py:class:`MarkInfo` -instance. You can also specify parametrized meta data like this:: +instance. You can also specify parametrized metadata like this:: # content of test_mark.py @@ -44,7 +44,7 @@ Marking whole classes or modules ---------------------------------------------------- If you are programming with Python2.6 you may use ``pytest.mark`` decorators -with classes to apply markers to all its test methods:: +with classes to apply markers to all of its test methods:: # content of test_mark_classlevel.py import pytest @@ -88,7 +88,7 @@ You can use the ``-k`` command line option to select tests:: $ py.test -k webtest # running with the above defined examples yields =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 4 items test_mark.py .. @@ -100,7 +100,7 @@ And you can also run all tests except the ones that match the keyword:: $ py.test -k-webtest =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 4 items ===================== 4 tests deselected by '-webtest' ===================== @@ -110,7 +110,7 @@ Or to only select the class:: $ py.test -kTestClass =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 4 items test_mark_classlevel.py .. diff --git a/doc/monkeypatch.txt b/doc/monkeypatch.txt index 1d46ffe0a..c5f42adbd 100644 --- a/doc/monkeypatch.txt +++ b/doc/monkeypatch.txt @@ -9,8 +9,8 @@ on global settings or which invokes code which cannot be easily tested such as network access. The ``monkeypatch`` function argument helps you to safely set/delete an attribute, dictionary item or environment variable or to modify ``sys.path`` for importing. -See the `monkeypatch blog post`_ one some introduction material -and motivation. +See the `monkeypatch blog post`_ for some introduction material +and a discussion of its motivation. .. _`monkeypatch blog post`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/ @@ -18,7 +18,7 @@ and motivation. Simple example: patching ``os.path.expanduser`` --------------------------------------------------- -If you e.g. want to pretend that ``os.expanduser`` returns a certain +If, for instance, you want to pretend that ``os.expanduser`` returns a certain directory, you can use the :py:meth:`monkeypatch.setattr` method to patch this function before calling into a function which uses it:: @@ -39,7 +39,7 @@ will be undone. .. background check: $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 0 items ============================= in 0.00 seconds ============================= diff --git a/doc/naming20.txt b/doc/naming20.txt index 9fc7ae99f..5a81df269 100644 --- a/doc/naming20.txt +++ b/doc/naming20.txt @@ -16,5 +16,5 @@ these renaming rules:: py.test.cmdline.main -> pytest.main The old ``py.test.*`` ways to access functionality remain -valid but you are encouraged to do global renames according +valid but you are encouraged to do global renaming according to the above rules in your test code. diff --git a/doc/plugins.txt b/doc/plugins.txt index 620b00fac..eeece1805 100644 --- a/doc/plugins.txt +++ b/doc/plugins.txt @@ -1,8 +1,8 @@ +.. _plugins: + Working with plugins and conftest files ============================================= -.. _`local plugin`: - py.test implements all aspects of configuration, collection, running and reporting by calling `well specified hooks`_. Virtually any Python module can be registered as a plugin. It can implement any number of hook functions (usually two or three) which all have a ``pytest_`` prefix, making hook functions easy to distinguish and find. There are three basic locations types: * `builtin plugins`_: loaded from py.test's own ``pytest/plugin`` directory. @@ -12,14 +12,17 @@ py.test implements all aspects of configuration, collection, running and reporti .. _`pytest/plugin`: http://bitbucket.org/hpk42/pytest/src/tip/pytest/plugin/ .. _`conftest.py plugins`: .. _`conftest.py`: +.. _`localplugin`: +.. _`conftest`: conftest.py: local per-directory plugins -------------------------------------------------------------- local ``conftest.py`` plugins contain directory-specific hook implementations. Session and test running activities will -invoke all hooks defined in "higher up" ``conftest.py`` files. -Example: Assume the following layout and content of files:: +invoke all hooks defined in ``conftest.py`` files closer to the +root of the filesystem. Example: Assume the following layout +and content of files:: a/conftest.py: def pytest_runtest_setup(item): @@ -39,11 +42,6 @@ Here is how you might run it:: py.test test_flat.py # will not show "setting up" py.test a/test_sub.py # will show "setting up" -A note on ordering: ``py.test`` loads all ``conftest.py`` files upwards -from the command line file arguments. It usually performs look up -right-to-left, i.e. the hooks in "closer" conftest files will be called -earlier than further away ones. - .. Note:: If you have ``conftest.py`` files which do not reside in a python package directory (i.e. one containing an ``__init__.py``) then @@ -112,12 +110,12 @@ Making your plugin installable by others ----------------------------------------------- If you want to make your plugin externally available, you -may define a so called entry point for your distribution so +may define a so-called entry point for your distribution so that ``py.test`` finds your plugin module. Entry points are a feature that is provided by `setuptools`_ or `Distribute`_. -The concrete entry point is ``pytest11``. To make your plugin -available you can insert the following lines in your -setuptools/distribute-based setup-invocation: +py.test looks up the ``pytest11`` entrypoint to discover its +plugins and you can thus make your plugin available by definig +it in your setuptools/distribute-based setup-invocation: .. sourcecode:: python @@ -137,8 +135,8 @@ setuptools/distribute-based setup-invocation: ) If a package is installed this way, py.test will load -``myproject.pluginmodule`` and accordingly call functions -if they match the `well specified hooks`_. +``myproject.pluginmodule`` as a plugin which can define +`well specified hooks`_. Plugin discovery order at tool startup -------------------------------------------- @@ -260,11 +258,11 @@ hook specification and validation py.test calls hook functions to implement initialization, running, test execution and reporting. When py.test loads a plugin it validates -that all hook functions conform to their respective hook specification. +that each hook function conforms to its respective hook specification. Each hook function name and its argument names need to match a hook -specification exactly but it is allowed for a hook function to accept -*less* parameters than specified. If you mistype argument names or the -hook name itself you get useful errors. +specification. However, a hook function may accept *fewer* parameters +by simply not specifying them. If you mistype argument names or the +hook name itself you get an error showing the available arguments. initialisation, command line and configuration hooks -------------------------------------------------------------------- @@ -292,8 +290,9 @@ All all runtest related hooks receive a :py:class:`pytest.Item` object. For deeper understanding you may look at the default implementation of these hooks in :py:mod:`_pytest.runner` and maybe also -in :py:mod:`_pytest.pdb` which intercepts creation -of reports in order to drop to interactive debugging. +in :py:mod:`_pytest.pdb` which interacts with :py:mod:`_pytest.capture` +and its input/output capturing in order to immediately drop +into interactive debugging when a test failure occurs. The :py:mod:`_pytest.terminal` reported specifically uses the reporting hook to print information about a test run. diff --git a/doc/projects.txt b/doc/projects.txt index 4389e424c..4226ab467 100644 --- a/doc/projects.txt +++ b/doc/projects.txt @@ -46,7 +46,7 @@ Some organisations using py.test * `Shootq `_ * `Stups department of Heinrich Heine University Düsseldorf `_ * `cellzome `_ -* `Open End, Gotenborg `_ +* `Open End, Gothenborg `_ * `Laboraratory of Bioinformatics, Warsaw `_ * `merlinux, Germany `_ * many more ... (please be so kind to send a note via :ref:`contact`) diff --git a/doc/pytest.ini b/doc/pytest.ini index 01e3f9d29..760436056 100644 --- a/doc/pytest.ini +++ b/doc/pytest.ini @@ -1,2 +1,2 @@ [pytest] -# just defined to prevent the root level tox.ini to kick in +# just defined to prevent the root level tox.ini from kicking in diff --git a/doc/skipping.txt b/doc/skipping.txt index 63ea6eda3..94164ebd2 100644 --- a/doc/skipping.txt +++ b/doc/skipping.txt @@ -5,19 +5,18 @@ skip and xfail mechanisms ===================================================================== You can skip or "xfail" test functions, either by marking functions -through a decorator or by calling the ``pytest.skip|xfail`` functions. +with a decorator or by calling the ``pytest.skip|xfail`` functions. A *skip* means that you expect your test to pass unless a certain configuration or condition (e.g. wrong Python interpreter, missing dependency) prevents it to run. And *xfail* means that you expect your test to fail because there is an implementation problem. py.test counts and lists *xfailing* tests separately -and you can provide info such as a bug number or a URL to provide a -human readable problem context. +and it is possible to give additional information, such as bug number or a URL. -Usually detailed information about skipped/xfailed tests is not shown +Detailed information about skipped/xfailed tests is by default not shown at the end of a test run to avoid cluttering the output. You can use the ``-r`` option to see details corresponding to the "short" letters shown in the test progress:: - py.test -rxs # show extra info on skips and xfail tests + py.test -rxs # show extra info on skips and xfails (See :ref:`how to change command line options defaults`) @@ -26,7 +25,7 @@ shown in the test progress:: Skipping a single function ------------------------------------------- -Here is an example for marking a test function to be skipped +Here is an example of marking a test function to be skipped when run on a Python3 interpreter:: import sys @@ -60,7 +59,7 @@ on a test configuration value:: def test_function(...): ... -Create a shortcut for your conditional skip decorator +You can create a shortcut for your conditional skip decorator at module level like this:: win32only = pytest.mark.skipif("sys.platform != 'win32'") @@ -73,9 +72,9 @@ at module level like this:: skip all test functions of a class -------------------------------------- -As with all function :ref:`marking` you can do it at +As with all function :ref:`mark` you can skip test functions at the `whole class- or module level`_. Here is an example -for skipping all methods of a test class based on platform:: +for skipping all methods of a test class based on the platform:: class TestPosixCalls: pytestmark = pytest.mark.skipif("sys.platform == 'win32'") @@ -93,9 +92,7 @@ the skipif decorator on classes:: def test_function(self): "will not be setup or run under 'win32' platform" -It is fine in general to apply multiple "skipif" decorators -on a single function - this means that if any of the conditions -apply the function will be skipped. +Using multiple "skipif" decorators on a single function is generally fine - it means that if any of the conditions apply the function execution will be skipped. .. _`whole class- or module level`: mark.html#scoped-marking @@ -122,16 +119,16 @@ By specifying on the commandline:: you can force the running and reporting of an ``xfail`` marked test as if it weren't marked at all. -Same as with skipif_ you can also selectively expect a failure -depending on platform:: +As with skipif_ you can also mark your expectation of a failure +on a particular platform:: @pytest.mark.xfail("sys.version_info >= (3,0)") def test_function(): ... -You can also avoid running an "xfail" test at all or +You can furthermore prevent the running of an "xfail" test or specify a reason such as a bug ID or similar. Here is -a simple test file with usages: +a simple test file with the several usages: .. literalinclude:: example/xfail_demo.py @@ -139,10 +136,10 @@ Running it with the report-on-xfail option gives this output:: example $ py.test -rx xfail_demo.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 - collecting ... collected 5 items + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + collecting ... collected 6 items - xfail_demo.py xxxxx + xfail_demo.py xxxxxx ========================= short test summary info ========================== XFAIL xfail_demo.py::test_hello XFAIL xfail_demo.py::test_hello2 @@ -152,9 +149,11 @@ Running it with the report-on-xfail option gives this output:: XFAIL xfail_demo.py::test_hello4 bug 110 XFAIL xfail_demo.py::test_hello5 + condition: pytest.__version__[0] != "17" + XFAIL xfail_demo.py::test_hello6 reason: reason - ======================== 5 xfailed in 0.04 seconds ========================= + ======================== 6 xfailed in 0.06 seconds ========================= imperative xfail from within a test or setup function ------------------------------------------------------ @@ -177,8 +176,8 @@ or within a test or test setup function:: docutils = pytest.importorskip("docutils") If ``docutils`` cannot be imported here, this will lead to a -skip outcome of the test. You can also skip depending if -if a library does not come with a high enough version:: +skip outcome of the test. You can also skip based on the +version number of a library:: docutils = pytest.importorskip("docutils", minversion="0.3") @@ -188,7 +187,7 @@ imperative skip from within a test or setup function ------------------------------------------------------ If for some reason you cannot declare skip-conditions -you can also imperatively produce a Skip-outcome from +you can also imperatively produce a skip-outcome from within test or setup code. Example:: def test_function(): diff --git a/doc/tmpdir.txt b/doc/tmpdir.txt index b5a96596d..9b0622feb 100644 --- a/doc/tmpdir.txt +++ b/doc/tmpdir.txt @@ -28,7 +28,7 @@ Running this would result in a passed test except for the last $ py.test test_tmpdir.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_tmpdir.py F @@ -36,7 +36,7 @@ Running this would result in a passed test except for the last ================================= FAILURES ================================= _____________________________ test_create_file _____________________________ - tmpdir = local('/tmp/pytest-102/test_create_file0') + tmpdir = local('/tmp/pytest-93/test_create_file0') def test_create_file(tmpdir): p = tmpdir.mkdir("sub").join("hello.txt") @@ -47,14 +47,14 @@ Running this would result in a passed test except for the last E assert 0 test_tmpdir.py:7: AssertionError - ========================= 1 failed in 0.03 seconds ========================= + ========================= 1 failed in 0.04 seconds ========================= .. _`base temporary directory`: the default base temporary directory ----------------------------------------------- -Temporary directories are by default created as sub directories of +Temporary directories are by default created as sub-directories of the system temporary directory. The base name will be ``pytest-NUM`` where ``NUM`` will be incremented with each test run. Moreover, entries older than 3 temporary directories will be removed. diff --git a/doc/unittest.txt b/doc/unittest.txt index 783c44c42..11a249724 100644 --- a/doc/unittest.txt +++ b/doc/unittest.txt @@ -8,7 +8,7 @@ py.test has limited support for running Python `unittest.py style`_ tests. It will automatically collect ``unittest.TestCase`` subclasses and their ``test`` methods in test files. It will invoke ``setUp/tearDown`` methods but also perform py.test's standard ways -of treating tests like e.g. IO capturing:: +of treating tests such as IO capturing:: # content of test_unittest.py @@ -24,7 +24,7 @@ Running it yields:: $ py.test test_unittest.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_unittest.py F diff --git a/doc/usage.txt b/doc/usage.txt index fa83019bd..98b6fd4e4 100644 --- a/doc/usage.txt +++ b/doc/usage.txt @@ -12,7 +12,7 @@ calling pytest through ``python -m pytest`` .. versionadded:: 2.0 -If you use Python-2.5 or above you can invoke testing through the +If you use Python-2.5 or later you can invoke testing through the Python interpreter from the command line:: python -m pytest [...] @@ -20,8 +20,8 @@ Python interpreter from the command line:: This is equivalent to invoking the command line script ``py.test [...]`` directly. -Getting help on version, option names, environment vars ------------------------------------------------------------ +Getting help on version, option names, environment variables +-------------------------------------------------------------- :: @@ -96,7 +96,7 @@ can use a helper:: .. versionadded: 2.0.0 In previous versions you could only enter PDB tracing if -you :ref:`disable capturing`. +you disable capturing on the command line via ``py.test -s``. creating JUnitXML format files ---------------------------------------------------- diff --git a/doc/xdist.txt b/doc/xdist.txt index 7b70b33cf..6aa4be117 100644 --- a/doc/xdist.txt +++ b/doc/xdist.txt @@ -7,13 +7,13 @@ xdist: pytest distributed testing plugin The `pytest-xdist`_ plugin extends py.test with some unique test execution modes: -* Looponfail: run your tests repeatedly in a subprocess. After each run py.test - waits until a file in your project changes and then re-runs the previously - failing tests. This is repeated until all tests pass after which again - a full run is performed. +* Looponfail: run your tests repeatedly in a subprocess. After each + run, py.test waits until a file in your project changes and then + re-runs the previously failing tests. This is repeated until all + tests pass. At this point a full run is again performed. * multiprocess Load-balancing: if you have multiple CPUs or hosts you can use - those for a combined test run. This allows to speed up + them for a combined test run. This allows to speed up development or to use special resources of remote machines. * Multi-Platform coverage: you can specify different Python interpreters @@ -25,8 +25,8 @@ are reported back and displayed to your local terminal. You may specify different Python versions and interpreters. -Installation ------------------------ +Installation of xdist plugin +------------------------------ Install the plugin with:: @@ -55,13 +55,13 @@ To send tests to multiple CPUs, type:: py.test -n NUM Especially for longer running tests or tests requiring -a lot of IO this can lead to considerable speed ups. +a lot of I/O this can lead to considerable speed ups. Running tests in a Python subprocess +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -To instantiate a python2.4 sub process and send tests to it, you may type:: +To instantiate a Python-2.4 subprocess and send tests to it, you may type:: py.test -d --tx popen//python=python2.4 @@ -70,10 +70,10 @@ Python interpreter, found in your system binary lookup path. If you prefix the --tx option value like this:: - --tx 3*popen//python=python2.4 + py.test -d --tx 3*popen//python=python2.4 -then three subprocesses would be created and tests -will be load-balanced across these three processes. +then three subprocesses would be created and the tests +will be distributed to three subprocesses and run simultanously. .. _looponfailing: @@ -82,11 +82,13 @@ Running tests in looponfailing mode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ For refactoring a project with a medium or large test suite -you can use the looponfailing mode, simply add the ``--f`` option:: +you can use the looponfailing mode. Simply add the ``--f`` option:: py.test -f -and py.test will run your tests, then wait for file changes and re-run the failing test set. Of course you can pass in more options to select tests or test files. File changes are detected by looking at the root directory - you can override this automatic default by an ini-file setting:: +and py.test will run your tests. Assuming you have failures it will then +wait for file changes and re-run the failing test set. File changes are detected by looking at ``looponfailingroots`` root directories and all of their contents (recursively). If the default for this value does not work for you you +can change it in your project by setting a configuration option:: # content of a pytest.ini, setup.cfg or tox.ini file [pytest] @@ -98,26 +100,28 @@ Sending tests to remote SSH accounts +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Suppose you have a package ``mypkg`` which contains some -tests that you can successfully run locally. And you +tests that you can successfully run locally. And you also have a ssh-reachable machine ``myhost``. Then you can ad-hoc distribute your tests by typing:: py.test -d --tx ssh=myhostpopen --rsyncdir mypkg mypkg This will synchronize your ``mypkg`` package directory -to an remote ssh account and then locally collect tests -and send them to remote places for execution. +with a remote ssh account and then collect and run your +tests at the remote side. You can specify multiple ``--rsyncdir`` directories to be sent to the remote side. -**NOTE:** For py.test to collect and send tests correctly -you not only need to make sure all code and tests -directories are rsynced, but that any test (sub) directory -also has an ``__init__.py`` file because internally -py.test references tests as a fully qualified python -module path. **You will otherwise get strange errors** -during setup of the remote side. +.. XXX CHECK + + **NOTE:** For py.test to collect and send tests correctly + you not only need to make sure all code and tests + directories are rsynced, but that any test (sub) directory + also has an ``__init__.py`` file because internally + py.test references tests as a fully qualified python + module path. **You will otherwise get strange errors** + during setup of the remote side. Sending tests to remote Socket Servers +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -158,8 +162,7 @@ Specifying test exec environments in an ini file +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pytest (since version 2.0) supports ini-style configuration. -You can for example make running with three subprocesses -your default like this:: +For example, you could make running with three subprocesses your default:: [pytest] addopts = -n3 diff --git a/doc/xunit_setup.txt b/doc/xunit_setup.txt index 77e8d552d..486d1cc45 100644 --- a/doc/xunit_setup.txt +++ b/doc/xunit_setup.txt @@ -65,7 +65,7 @@ Similarly, the following methods are called around each method invocation:: with a setup_method call. """ -If you rather define test functions directly at module level +If you would rather define test functions directly at module level you can also use the following functions to implement fixtures:: def setup_function(function):