Skip to content

Commit c685576

Browse files
committed
Merge branch 'scope' into develop
2 parents 7a80ae7 + 0b40d65 commit c685576

14 files changed

+1004
-28
lines changed

doc/examples/nodeid.out

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
$ pytest --verbose
2+
============================= test session starts ==============================
3+
platform linux -- Python 3.8.1, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- /usr/bin/python3
4+
cachedir: .pytest_cache
5+
rootdir: /home/user
6+
plugins: dependency-0.4.0
7+
collected 7 items
8+
9+
tests/test_nodeid.py::test_a PASSED [ 14%]
10+
tests/test_nodeid.py::test_b[7-True] PASSED [ 28%]
11+
tests/test_nodeid.py::test_b[0-False] PASSED [ 42%]
12+
tests/test_nodeid.py::test_b[-1-False] XFAIL [ 57%]
13+
tests/test_nodeid.py::TestClass::test_c PASSED [ 71%]
14+
tests/test_nodeid.py::TestClass::test_d[order] PASSED [ 85%]
15+
tests/test_nodeid.py::TestClass::test_d[disorder] PASSED [100%]
16+
17+
========================= 6 passed, 1 xfailed in 0.08s =========================

doc/examples/nodeid.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import random
2+
import pytest
3+
4+
def test_a():
5+
pass
6+
7+
@pytest.mark.parametrize("i,b", [
8+
(7, True),
9+
(0, False),
10+
pytest.param(-1, False, marks=pytest.mark.xfail(reason="nonsense"))
11+
])
12+
def test_b(i, b):
13+
assert bool(i) == b
14+
15+
ordered = list(range(10))
16+
unordered = random.sample(ordered, k=len(ordered))
17+
18+
class TestClass:
19+
20+
def test_c(self):
21+
pass
22+
23+
@pytest.mark.parametrize("l,ll", [(ordered, 10), (unordered, 10)],
24+
ids=["order", "disorder"])
25+
def test_d(self, l, ll):
26+
assert len(l) == ll

doc/examples/scope_class.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import pytest
2+
3+
@pytest.mark.dependency()
4+
@pytest.mark.xfail(reason="deliberate fail")
5+
def test_a():
6+
assert False
7+
8+
9+
class TestClass1(object):
10+
11+
@pytest.mark.dependency()
12+
def test_b(self):
13+
pass
14+
15+
16+
class TestClass2(object):
17+
18+
@pytest.mark.dependency()
19+
def test_a(self):
20+
pass
21+
22+
@pytest.mark.dependency(depends=["test_a"])
23+
def test_c(self):
24+
pass
25+
26+
@pytest.mark.dependency(depends=["test_a"], scope='class')
27+
def test_d(self):
28+
pass
29+
30+
@pytest.mark.dependency(depends=["test_b"], scope='class')
31+
def test_e(self):
32+
pass

doc/examples/scope_module.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import pytest
2+
3+
@pytest.mark.dependency()
4+
@pytest.mark.xfail(reason="deliberate fail")
5+
def test_a():
6+
assert False
7+
8+
@pytest.mark.dependency()
9+
def test_b():
10+
pass
11+
12+
@pytest.mark.dependency(depends=["test_a"], scope='module')
13+
def test_c():
14+
pass
15+
16+
@pytest.mark.dependency(depends=["test_b"], scope='module')
17+
def test_d():
18+
pass
19+
20+
@pytest.mark.dependency(depends=["test_b", "test_c"], scope='module')
21+
def test_e():
22+
pass

doc/examples/scope_session_mod_01.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# test_mod_01.py
2+
3+
import pytest
4+
5+
@pytest.mark.dependency()
6+
def test_a():
7+
pass
8+
9+
@pytest.mark.dependency()
10+
@pytest.mark.xfail(reason="deliberate fail")
11+
def test_b():
12+
assert False
13+
14+
@pytest.mark.dependency(depends=["test_a"])
15+
def test_c():
16+
pass
17+
18+
19+
class TestClass(object):
20+
21+
@pytest.mark.dependency()
22+
def test_b(self):
23+
pass

doc/examples/scope_session_mod_02.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# test_mod_02.py
2+
3+
import pytest
4+
5+
@pytest.mark.dependency()
6+
@pytest.mark.xfail(reason="deliberate fail")
7+
def test_a():
8+
assert False
9+
10+
@pytest.mark.dependency(
11+
depends=["tests/test_mod_01.py::test_a", "tests/test_mod_01.py::test_c"],
12+
scope='session'
13+
)
14+
def test_e():
15+
pass
16+
17+
@pytest.mark.dependency(
18+
depends=["tests/test_mod_01.py::test_b", "tests/test_mod_02.py::test_e"],
19+
scope='session'
20+
)
21+
def test_f():
22+
pass
23+
24+
@pytest.mark.dependency(
25+
depends=["tests/test_mod_01.py::TestClass::test_b"],
26+
scope='session'
27+
)
28+
def test_g():
29+
pass

doc/src/changelog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ History of changes to pytest-dependency
22
=======================================
33

44
dev (not yet released)
5+
New features
6+
+ Issue #3, PR #35: add a scope to dependencies.
7+
58
Bug fixes and minor changes
69
+ Issue #34: failing test with pytest 4.2.0 and newer.
710

doc/src/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ Content of the documentation
1414
about
1515
install
1616
usage
17+
scope
1718
advanced
19+
names
1820
configuration
1921
changelog
2022
reference

doc/src/names.rst

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
.. _names:
2+
3+
Names
4+
=====
5+
6+
Dependencies of tests are referenced by name. The default name is the
7+
`node id`__ assigned to the test by pytest. This default may be
8+
overridden by an explicit `name` argument to the
9+
:func:`pytest.mark.dependency` marker. The references also depend on
10+
the scope.
11+
12+
.. __: https://docs.pytest.org/en/latest/example/markers.html#node-id
13+
14+
Node ids
15+
--------
16+
17+
The node ids in pytest are built of several components, separated by a
18+
double colon "::". For test functions, these components are the
19+
relative path of the test module and the name of the function. In the
20+
case of a method of a test class the components are the module path,
21+
the name of the class, and the name of the method. If the function or
22+
method is parameterized, the parameter values, separated by minus "-",
23+
in square brackets "[]" are appended to the node id. The
24+
representation of the parameter values in the node id may be
25+
overridden using the `ids` argument to the
26+
`pytest.mark.parametrize()`__ marker.
27+
28+
.. __: https://docs.pytest.org/en/latest/reference.html#pytest-mark-parametrize-ref
29+
30+
31+
One may check the node ids of all tests calling pytest with the
32+
`--verbose` command line option. As an example, consider the
33+
following test module:
34+
35+
.. literalinclude:: ../examples/nodeid.py
36+
37+
If this module is stored as `tests/test_nodeid.py`, the output will
38+
look like:
39+
40+
.. literalinclude:: ../examples/nodeid.out
41+
42+
.. note::
43+
Old versions of pytest used to include an extra "()" component to
44+
the node ids of methods of test classes. This has been
45+
`removed in pytest 4.0.0`__. pytest-dependency strips this
46+
if present. Thus, when referencing dependencies, the new style
47+
node ids as described above may (and must) be used, regardless of
48+
the pytest version.
49+
50+
.. __: https://docs.pytest.org/en/latest/changelog.html#pytest-4-0-0-2018-11-13
51+
52+
References and scope
53+
--------------------
54+
55+
When referencing dependencies of tests, the names to be used in the
56+
`depends` argument to the :func:`pytest.mark.dependency` marker or the
57+
`other` argument to the :func:`pytest_dependency.depends` function
58+
depend on the scope as follows:
59+
60+
`session`
61+
The full node id must be used.
62+
`package`
63+
The full node id must be used.
64+
`module`
65+
The node id with the leading module path including the "::"
66+
separator removed must be used.
67+
`class`
68+
The node id with the module path and the class name including the
69+
"::" separator removed must be used.
70+
71+
That is, in the example above, when referencing `test_a` as a
72+
dependency, it must be referenced as `tests/test_nodeid.py::test_a` in
73+
session scope and as `test_a` in module scope. When referencing the
74+
first invocation of `test_d` as a dependency, it must be referenced as
75+
`tests/test_nodeid.py::TestClass::test_d[order]` in session scope, as
76+
`TestClass::test_d[order]` in module scope, and as `test_d[order]` in
77+
class scope.
78+
79+
If the name of the dependency has been set with an explicit `name`
80+
argument to the :func:`pytest.mark.dependency` marker, this name must
81+
always be used as is, regardless of the scope.
82+
83+
.. note::
84+
The module path in the node id is the path relative to the current
85+
working directory. This depends on the invocation of pytest. In
86+
the example above, if you change into the `tests` directory before
87+
invoking pytest, the module path in the node ids will be
88+
`test_nodeid.py`. If you use references in session scope, you'll
89+
need to make sure pytest is always invoked from the same working
90+
directory.

doc/src/reference.rst

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Reference
22
=========
33

4-
.. py:decorator:: pytest.mark.dependency(name=None, depends=[])
4+
.. py:decorator:: pytest.mark.dependency(name=None, depends=[], scope='module')
55
66
Mark a test to be used as a dependency for other tests or to
77
depend on other tests.
@@ -11,16 +11,25 @@ Reference
1111
for the test may be set in the depends argument.
1212

1313
:param name: the name of the test to be used for referencing by
14-
dependent tests. If not set, it defaults to the node ID
15-
defined by pytest, that is the name of the test function,
16-
extended by the parameters if applicable. The name must be
17-
unique in the scope, which is currently the test module.
14+
dependent tests. If not set, it defaults to the node ID
15+
defined by pytest. The name must be unique.
1816
:type name: :class:`str`
1917
:param depends: dependencies, a list of names of tests that this
2018
test depends on. The test will be skipped unless all of the
21-
dependencies have been run successfully. The dependencies
22-
must also have been decorated by the marker.
19+
dependencies have been run successfully. The dependencies
20+
must also have been decorated by the marker. The names of the
21+
dependencies must be adapted to the scope.
2322
:type depends: iterable of :class:`str`
23+
:param scope: the scope to search for the dependencies. Must be
24+
either `'session'`, `'package'`, `'module'`, or `'class'`.
25+
:type scope: :class:`str`
26+
27+
See Section :ref:`names` for details on the default name if the
28+
`name` argument is not set and on how references in the `depends`
29+
argument must be adapted to the scope.
30+
31+
.. versionchanged:: 0.5.0
32+
the scope parameter has been added.
2433

2534
.. py:module:: pytest_dependency
2635

0 commit comments

Comments
 (0)