clarify and add to sort-by-session-scoped parametrized resources example

This commit is contained in:
holger krekel 2012-07-23 10:54:57 +02:00
parent 6b0f0adf5b
commit 76584b53a1
1 changed files with 63 additions and 48 deletions

View File

@ -38,8 +38,8 @@ function is called three times. Let's run it::
$ py.test -q $ py.test -q
collecting ... collected 3 items collecting ... collected 3 items
..F ..F
=================================== FAILURES =================================== ================================= FAILURES =================================
______________________________ test_eval[6*9-42] _______________________________ ____________________________ test_eval[6*9-42] _____________________________
input = '6*9', expected = 42 input = '6*9', expected = 42
@ -104,8 +104,8 @@ let's run the full monty::
$ py.test -q --all $ py.test -q --all
collecting ... collected 5 items collecting ... collected 5 items
....F ....F
=================================== FAILURES =================================== ================================= FAILURES =================================
_______________________________ test_compute[4] ________________________________ _____________________________ test_compute[4] ______________________________
param1 = 4 param1 = 4
@ -153,21 +153,21 @@ only have to work a bit to construct the correct arguments for pytest's
this is a fully self-contained example which you can run with:: this is a fully self-contained example which you can run with::
$ py.test test_scenarios.py $ py.test test_scenarios.py
============================= test session starts ============================== =========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- pytest-2.3.0.dev2 platform linux2 -- Python 2.7.3 -- pytest-2.3.0.dev3
plugins: xdist, bugzilla, cache, oejskit, cli, pep8, cov plugins: xdist, bugzilla, cache, oejskit, cli, pep8, cov
collecting ... collected 2 items collecting ... collected 2 items
test_scenarios.py .. test_scenarios.py ..
=========================== 2 passed in 0.02 seconds =========================== ========================= 2 passed in 0.02 seconds =========================
If you just collect tests you'll also nicely see 'advanced' and 'basic' as variants for the test function:: If you just collect tests you'll also nicely see 'advanced' and 'basic' as variants for the test function::
$ py.test --collectonly test_scenarios.py $ py.test --collectonly test_scenarios.py
============================= test session starts ============================== =========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- pytest-2.3.0.dev2 platform linux2 -- Python 2.7.3 -- pytest-2.3.0.dev3
plugins: xdist, bugzilla, cache, oejskit, cli, pep8, cov plugins: xdist, bugzilla, cache, oejskit, cli, pep8, cov
collecting ... collected 2 items collecting ... collected 2 items
<Module 'test_scenarios.py'> <Module 'test_scenarios.py'>
@ -176,7 +176,7 @@ If you just collect tests you'll also nicely see 'advanced' and 'basic' as varia
<Function 'test_demo[basic]'> <Function 'test_demo[basic]'>
<Function 'test_demo[advanced]'> <Function 'test_demo[advanced]'>
=============================== in 0.01 seconds =============================== ============================= in 0.02 seconds =============================
Deferring the setup of parametrized resources Deferring the setup of parametrized resources
--------------------------------------------------- ---------------------------------------------------
@ -223,25 +223,25 @@ creates a database object for the actual test invocations::
Let's first see how it looks like at collection time:: Let's first see how it looks like at collection time::
$ py.test test_backends.py --collectonly $ py.test test_backends.py --collectonly
============================= test session starts ============================== =========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- pytest-2.3.0.dev2 platform linux2 -- Python 2.7.3 -- pytest-2.3.0.dev3
plugins: xdist, bugzilla, cache, oejskit, cli, pep8, cov plugins: xdist, bugzilla, cache, oejskit, cli, pep8, cov
collecting ... collected 2 items collecting ... collected 2 items
<Module 'test_backends.py'> <Module 'test_backends.py'>
<Function 'test_db_initialized[d1]'> <Function 'test_db_initialized[d1]'>
<Function 'test_db_initialized[d2]'> <Function 'test_db_initialized[d2]'>
=============================== in 0.01 seconds =============================== ============================= in 0.02 seconds =============================
And then when we run the test:: And then when we run the test::
$ py.test -q test_backends.py $ py.test -q test_backends.py
collecting ... collected 2 items collecting ... collected 2 items
.F .F
=================================== FAILURES =================================== ================================= FAILURES =================================
___________________________ test_db_initialized[d2] ____________________________ _________________________ test_db_initialized[d2] __________________________
db = <conftest.DB2 instance at 0x2df8fc8> db = <conftest.DB2 instance at 0x26bcea8>
def test_db_initialized(db): def test_db_initialized(db):
# a dummy test # a dummy test
@ -295,10 +295,10 @@ argument sets to use for each test function. Let's run it::
$ py.test -q $ py.test -q
collecting ... collected 3 items collecting ... collected 3 items
F.. F..
=================================== FAILURES =================================== ================================= FAILURES =================================
__________________________ TestClass.test_equals[1-2] __________________________ ________________________ TestClass.test_equals[1-2] ________________________
self = <test_parametrize.TestClass instance at 0x1e11830>, a = 1, b = 2 self = <test_parametrize.TestClass instance at 0x2fa9050>, a = 1, b = 2
def test_equals(self, a, b): def test_equals(self, a, b):
> assert a == b > assert a == b
@ -326,9 +326,9 @@ Running it results in some skips if we don't have all the python interpreters in
. $ py.test -rs -q multipython.py . $ py.test -rs -q multipython.py
collecting ... collected 75 items collecting ... collected 75 items
............sss............sss............sss............ssssssssssssssssss ............sss............sss............sss............ssssssssssssssssss
=========================== short test summary info ============================ ========================= short test summary info ==========================
SKIP [27] /home/hpk/p/pytest/doc/en/example/multipython.py:36: 'python2.8' not found SKIP [27] /home/hpk/p/pytest/doc/en/example/multipython.py:36: 'python2.8' not found
48 passed, 27 skipped in 1.89 seconds 48 passed, 27 skipped in 1.70 seconds
.. regendoc:wipe .. regendoc:wipe
@ -337,13 +337,13 @@ Grouping test execution by parameter
By default pytest will execute test functions by executing all its parametrized invocations. If you rather want to group execution by parameter, you can By default pytest will execute test functions by executing all its parametrized invocations. If you rather want to group execution by parameter, you can
use something like the following ``conftest.py`` example. It uses use something like the following ``conftest.py`` example. It uses
a parametrized "session" object:: a parametrized "resource" object::
# content of conftest.py # content of conftest.py
def pytest_collection_modifyitems(items): def pytest_collection_modifyitems(items):
def cmp(item1, item2): def cmp(item1, item2):
param1 = item1.callspec.getparam("session") param1 = item1.callspec.getparam("resource")
param2 = item2.callspec.getparam("session") param2 = item2.callspec.getparam("resource")
if param1 < param2: if param1 < param2:
return -1 return -1
elif param1 > param2: elif param1 > param2:
@ -352,49 +352,64 @@ a parametrized "session" object::
items.sort(cmp=cmp) items.sort(cmp=cmp)
def pytest_generate_tests(metafunc): def pytest_generate_tests(metafunc):
if "session" in metafunc.funcargnames: if "resource" in metafunc.funcargnames:
metafunc.parametrize("session", [1,2], indirect=True) metafunc.parametrize("resource", [1,2], indirect=True)
class Session: class Resource:
def __init__(self, num): def __init__(self, num):
self.num = num self.num = num
def finalize(self):
print "finalize", self
def pytest_funcarg__session(request): def pytest_funcarg__resource(request):
return Session(request.param) return request.cached_setup(lambda: Resource(request.param),
teardown=lambda res: res.finalize(),
extrakey=request.param)
If you know have a test file like this:: If you have a test file like this::
# content of test_session.py # content of test_resource.py
def test_hello(session): def test_hello(resource):
pass pass
def test_world(session): def test_world(resource):
pass pass
class TestClass: class TestClass:
def test_method1(self, session): def test_method1(self, resource):
pass pass
def test_method2(self, session): def test_method2(self, resource):
pass pass
then a subsequent execution will order the running of tests by then a subsequent execution will order the running of tests by
parameter value:: parameter value::
$ py.test -v $ py.test -v -s
============================= test session starts ============================== =========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- pytest-2.3.0.dev2 -- /home/hpk/venv/1/bin/python platform linux2 -- Python 2.7.3 -- pytest-2.3.0.dev3 -- /home/hpk/venv/1/bin/python
cachedir: /home/hpk/tmp/doc-exec-313/.cache cachedir: /home/hpk/tmp/doc-exec-340/.cache
plugins: xdist, bugzilla, cache, oejskit, cli, pep8, cov plugins: xdist, bugzilla, cache, oejskit, cli, pep8, cov
collecting ... collected 8 items collecting ... collected 8 items
test_session.py:1: test_hello[1] PASSED test_resource.py:1: test_hello[1] PASSED
test_session.py:4: test_world[1] PASSED test_resource.py:4: test_world[1] PASSED
test_session.py:8: TestClass.test_method1[1] PASSED test_resource.py:8: TestClass.test_method1[1] PASSED
test_session.py:10: TestClass.test_method2[1] PASSED test_resource.py:10: TestClass.test_method2[1] PASSED
test_session.py:1: test_hello[2] PASSED test_resource.py:1: test_hello[2] PASSED
test_session.py:4: test_world[2] PASSED test_resource.py:4: test_world[2] PASSED
test_session.py:8: TestClass.test_method1[2] PASSED test_resource.py:8: TestClass.test_method1[2] PASSED
test_session.py:10: TestClass.test_method2[2] PASSED test_resource.py:10: TestClass.test_method2[2] PASSED
=========================== 8 passed in 0.02 seconds =========================== ========================= 8 passed in 0.03 seconds =========================
finalize <conftest.Resource instance at 0x2e7f878>
finalize <conftest.Resource instance at 0x2e7ddd0>
.. note::
Despite the per-session ordering the finalize() of the session-scoped
resource executes at the end of the whole test session. The life
cycle of the two parametrized instantiated resources will thus overlap.
One possible workaround is to make the resource instantiations be
aware of each other and teardown the other one before returning a new
resource. There are plans for future releases of pytest to offer an
out-of-the-box way to support session-ordering.