Skip to content

Commit 817bcca

Browse files
committed
Merge branch 'doc'.
2 parents 6f88cc2 + 806ea8a commit 817bcca

File tree

10 files changed

+238
-4
lines changed

10 files changed

+238
-4
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ clean:
3030
distclean: clean
3131
rm -rf .cache tests/.cache
3232
rm -f MANIFEST
33-
rm -f *.pyc tests/*.pyc doc/examples/*.pyc
34-
rm -rf __pycache__ tests/__pycache__ doc/examples/__pycache__
33+
rm -f *.pyc tests/*.pyc
34+
rm -rf __pycache__ tests/__pycache__
3535
rm -rf dist
3636
rm -rf pytest_dependency.egg-info
3737
rm -f python2_6.patch

doc/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ doctest: $(SRCDIRS)
3232
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) doctest
3333

3434
clean:
35-
rm -f *~ src/*~
35+
rm -f *~ examples/*~ src/*~
3636

3737
distclean: clean
3838
rm -rf doctrees html latex linkcheck doctest
39+
rm -f examples/*.pyc
40+
rm -rf examples/__pycache__
3941

4042
src/_static:
4143
mkdir $@

doc/examples/all_params.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import pytest
2+
3+
def instances(name, params):
4+
def vstr(val):
5+
if isinstance(val, (list, tuple)):
6+
return "-".join([str(v) for v in val])
7+
else:
8+
return str(val)
9+
return ["%s[%s]" % (name, vstr(v)) for v in params]
10+
11+
12+
params_a = range(17)
13+
14+
@pytest.mark.parametrize("x", params_a)
15+
@pytest.mark.dependency()
16+
def test_a(x):
17+
if x == 13:
18+
pytest.xfail("deliberate fail")
19+
assert False
20+
else:
21+
pass
22+
23+
@pytest.mark.dependency(depends=instances("test_a", params_a))
24+
def test_b():
25+
pass
26+
27+
params_c = zip(range(0,8,2), range(2,6))
28+
29+
@pytest.mark.parametrize("x,y", params_c)
30+
@pytest.mark.dependency()
31+
def test_c(x, y):
32+
if x > y:
33+
pytest.xfail("deliberate fail")
34+
assert False
35+
else:
36+
pass
37+
38+
@pytest.mark.dependency(depends=instances("test_c", params_c))
39+
def test_d():
40+
pass
41+
42+
params_e = ['abc', 'def']
43+
44+
@pytest.mark.parametrize("s", params_e)
45+
@pytest.mark.dependency()
46+
def test_e(s):
47+
if 'e' in s:
48+
pytest.xfail("deliberate fail")
49+
assert False
50+
else:
51+
pass
52+
53+
@pytest.mark.dependency(depends=instances("test_e", params_e))
54+
def test_f():
55+
pass

doc/examples/dyn-parametrized.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import pytest
2+
3+
# Test data
4+
# Consider a bunch of Nodes, some of them are parents and some are children.
5+
6+
class Node(object):
7+
NodeMap = {}
8+
def __init__(self, name, parent=None):
9+
self.name = name
10+
self.children = []
11+
self.NodeMap[self.name] = self
12+
if parent:
13+
self.parent = self.NodeMap[parent]
14+
self.parent.children.append(self)
15+
else:
16+
self.parent = None
17+
def __str__(self):
18+
return self.name
19+
20+
parents = [ Node("a"), Node("b"), Node("c"), Node("d"), ]
21+
childs = [ Node("e", "a"), Node("f", "a"), Node("g", "a"),
22+
Node("h", "b"), Node("i", "c"), Node("j", "c"),
23+
Node("k", "d"), Node("l", "d"), Node("m", "d"), ]
24+
25+
# The test for the parent shall depend on the test of all its children.
26+
# Create enriched parameter lists, decorated with the dependency marker.
27+
28+
childparam = [
29+
pytest.mark.dependency(name="test_child[%s]" % c)(c) for c in childs
30+
]
31+
parentparam = [
32+
pytest.mark.dependency(
33+
name="test_parent[%s]" % p,
34+
depends=["test_child[%s]" % c for c in p.children]
35+
)(p) for p in parents
36+
]
37+
38+
@pytest.mark.parametrize("c", childparam)
39+
def test_child(c):
40+
if c.name == "l":
41+
pytest.xfail("deliberate fail")
42+
assert False
43+
44+
@pytest.mark.parametrize("p", parentparam)
45+
def test_parent(p):
46+
pass
47+

doc/examples/group-fixture.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import pytest
2+
from pytest_dependency import depends
3+
4+
@pytest.fixture(scope="module", params=range(1,10))
5+
def testcase(request):
6+
param = request.param
7+
return param
8+
9+
@pytest.mark.dependency()
10+
def test_a(testcase):
11+
if testcase % 7 == 0:
12+
pytest.xfail("deliberate fail")
13+
assert False
14+
15+
@pytest.mark.dependency()
16+
def test_b(request, testcase):
17+
depends(request, ["test_a[%d]" % testcase])
18+
pass

doc/examples/group-fixture2.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import pytest
2+
from pytest_dependency import depends
3+
4+
@pytest.fixture(scope="module", params=range(1,10))
5+
def testcase(request):
6+
param = request.param
7+
return param
8+
9+
@pytest.fixture(scope="module")
10+
def dep_testcase(request, testcase):
11+
depends(request, ["test_a[%d]" % testcase])
12+
return testcase
13+
14+
@pytest.mark.dependency()
15+
def test_a(testcase):
16+
if testcase % 7 == 0:
17+
pytest.xfail("deliberate fail")
18+
assert False
19+
20+
@pytest.mark.dependency()
21+
def test_b(dep_testcase):
22+
pass
23+
24+
@pytest.mark.dependency()
25+
def test_c(dep_testcase):
26+
pass

doc/src/advanced.rst

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
Advanced usage
2+
==============
3+
4+
This section contains some advanced examples for using
5+
pytest-dependency.
6+
7+
Dynamic compilation of marked parameters
8+
----------------------------------------
9+
10+
Sometimes, the parameter values for parametrized tests cannot easily
11+
be typed as a simple list. It may need to be compiled at run time
12+
depending on a set of test data. This also works together with
13+
marking dependencies in the individual test instances.
14+
15+
Consider the following example test module:
16+
17+
.. literalinclude:: ../examples/dyn-parametrized.py
18+
19+
In principle, this example works the very same way as the basic
20+
example for parametrized tests, see :ref:`usage-parametrized`. The
21+
only difference is that the lists of paramters are dynamically
22+
compiled beforehand. The test for child `l` deliberately fails, just
23+
to show the effect. As a consequence, the test for its parent `d`
24+
will be skipped.
25+
26+
Grouping tests using fixtures
27+
-----------------------------
28+
29+
pytest features the `automatic grouping of tests by fixture
30+
instances`__. This is particularly useful if there is a set of test
31+
cases and a series of tests shall be run for each of the test case
32+
respectively.
33+
34+
Consider the following example:
35+
36+
.. literalinclude:: ../examples/group-fixture.py
37+
38+
The test instances of `test_b` depend on `test_a` for the same
39+
parameter value. The test `test_a[7]` deliberately fails, as a
40+
consequence `test_b[7]` will be skipped. Note that we need to call
41+
:func:`pytest_dependency.depends` to mark the dependencies, because
42+
there is no way to use the :func:`pytest.mark.dependency` marker on
43+
the parameter values here.
44+
45+
If many tests in the series depend on a single test, it might be an
46+
option, to move the call to :func:`pytest_dependency.depends` in a
47+
fixture on its own. Consider:
48+
49+
.. literalinclude:: ../examples/group-fixture2.py
50+
51+
In this example, both `test_b[7]` and `test_c[7]` are skipped, because
52+
`test_a[7]` deliberately fails.
53+
54+
.. __: https://docs.pytest.org/en/latest/fixture.html#automatic-grouping-of-tests-by-fixture-instances
55+
56+
Depend on all instances of a parametrized test at once
57+
------------------------------------------------------
58+
59+
If a test depends on a all instances of a parametrized test at once,
60+
listing all of them in the :func:`pytest.mark.dependency` marker
61+
explicitly might not be the best solution. But you can dynamically
62+
compile these lists from the parameter values, as in the following
63+
example:
64+
65+
.. literalinclude:: ../examples/all_params.py
66+
67+
Here, `test_b`, `test_d`, and `test_f` will be skipped because they
68+
depend on all instances of `test_a`, `test_c`, and `test_e`
69+
respectively, but `test_a[13]`, `test_c[6-5]`, and `test_e[def]` fail.
70+
The list of the test instances is compiled in the helper function
71+
`instances()`.
72+
73+
Unfortunately you need knowledge how pytest encodes parameter values
74+
in test instance names to write this helper function. Note in
75+
particular how lists of parameter values are compiled into one single
76+
string in the case of multi parameter tests. But also note that this
77+
example of the `instances()` helper will only work for simple cases.
78+
It requires the parameter values to be scalars that can easily be
79+
converted to strings. And it will fail if the same list of parameters
80+
is passed to the same test more then once, because then, pytest will
81+
add an index to the name to disambiguate the parameter values.

doc/src/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ Content of the documentation
1414
about
1515
install
1616
usage
17+
advanced
1718
reference

doc/src/usage.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ set:
4747

4848
.. literalinclude:: ../examples/named.py
4949

50+
.. _usage-parametrized:
51+
5052
Parametrized tests
5153
------------------
5254

@@ -75,7 +77,7 @@ following example:
7577
.. literalinclude:: ../examples/runtime.py
7678

7779
Tests `test_c` and `test_d` set their dependencies at runtime calling
78-
:func:`pytest_dependency.depends`. The first argument is the values
80+
:func:`pytest_dependency.depends`. The first argument is the value
7981
of the `request` pytest fixture, the second argument is the list of
8082
dependencies. It has the same effect as passing this list as the
8183
`depends` argument to the :func:`pytest.mark.dependency` marker.

pytest_dependency.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ def depends(request, other):
7676
:param other: dependencies, a list of names of tests that this
7777
test depends on.
7878
:type other: iterable of :class:`str`
79+
80+
.. versionadded:: 0.2
7981
"""
8082
item = request.node
8183
manager = DependencyManager.getManager(item)

0 commit comments

Comments
 (0)