internally keep multiple applications of the same markers as separate
entities such that the new iter() API can iterate over pytest.mark function attributes, getting all such applications. See added example for more info.
This commit is contained in:
parent
85f2a78005
commit
ccc1b21ebd
|
@ -191,8 +191,7 @@ class MarkDecorator:
|
|||
holder = MarkInfo(self.markname, self.args, self.kwargs)
|
||||
setattr(func, self.markname, holder)
|
||||
else:
|
||||
holder.kwargs.update(self.kwargs)
|
||||
holder.args += self.args
|
||||
holder.add(self.args, self.kwargs)
|
||||
return func
|
||||
kw = self.kwargs.copy()
|
||||
kw.update(kwargs)
|
||||
|
@ -208,11 +207,23 @@ class MarkInfo:
|
|||
self.args = args
|
||||
#: keyword argument dictionary, empty if nothing specified
|
||||
self.kwargs = kwargs
|
||||
self._arglist = [(args, kwargs.copy())]
|
||||
|
||||
def __repr__(self):
|
||||
return "<MarkInfo %r args=%r kwargs=%r>" % (
|
||||
self.name, self.args, self.kwargs)
|
||||
|
||||
def add(self, args, kwargs):
|
||||
""" add a MarkInfo with the given args and kwargs. """
|
||||
self._arglist.append((args, kwargs))
|
||||
self.args += args
|
||||
self.kwargs.update(kwargs)
|
||||
|
||||
def __iter__(self):
|
||||
""" yield MarkInfo objects each relating to a marking-call. """
|
||||
for args, kwargs in self._arglist:
|
||||
yield MarkInfo(self.name, args, kwargs)
|
||||
|
||||
def pytest_itemcollected(item):
|
||||
if not isinstance(item, pytest.Function):
|
||||
return
|
||||
|
|
|
@ -25,26 +25,26 @@ You can "mark" a test function with custom metadata like this::
|
|||
You can then restrict a test run to only run tests marked with ``webtest``::
|
||||
|
||||
$ py.test -v -m webtest
|
||||
=========================== test session starts ============================
|
||||
platform darwin -- Python 2.7.1 -- pytest-2.2.1 -- /Users/hpk/venv/1/bin/python
|
||||
============================= test session starts ==============================
|
||||
platform darwin -- Python 2.7.1 -- pytest-2.2.2.dev3 -- /Users/hpk/venv/1/bin/python
|
||||
collecting ... collected 2 items
|
||||
|
||||
test_server.py:3: test_send_http PASSED
|
||||
|
||||
=================== 1 tests deselected by "-m 'webtest'" ===================
|
||||
================== 1 passed, 1 deselected in 0.01 seconds ==================
|
||||
===================== 1 tests deselected by "-m 'webtest'" =====================
|
||||
==================== 1 passed, 1 deselected in 0.03 seconds ====================
|
||||
|
||||
Or the inverse, running all tests except the webtest ones::
|
||||
|
||||
$ py.test -v -m "not webtest"
|
||||
=========================== test session starts ============================
|
||||
platform darwin -- Python 2.7.1 -- pytest-2.2.1 -- /Users/hpk/venv/1/bin/python
|
||||
============================= test session starts ==============================
|
||||
platform darwin -- Python 2.7.1 -- pytest-2.2.2.dev3 -- /Users/hpk/venv/1/bin/python
|
||||
collecting ... collected 2 items
|
||||
|
||||
test_server.py:6: test_something_quick PASSED
|
||||
|
||||
================= 1 tests deselected by "-m 'not webtest'" =================
|
||||
================== 1 passed, 1 deselected in 0.01 seconds ==================
|
||||
=================== 1 tests deselected by "-m 'not webtest'" ===================
|
||||
==================== 1 passed, 1 deselected in 0.03 seconds ====================
|
||||
|
||||
Registering markers
|
||||
-------------------------------------
|
||||
|
@ -134,6 +134,7 @@ You can also set a module level marker::
|
|||
in which case it will be applied to all functions and
|
||||
methods defined in the module.
|
||||
|
||||
|
||||
Using ``-k TEXT`` to select tests
|
||||
----------------------------------------------------
|
||||
|
||||
|
@ -141,39 +142,39 @@ You can use the ``-k`` command line option to only run tests with names matching
|
|||
the given argument::
|
||||
|
||||
$ py.test -k send_http # running with the above defined examples
|
||||
=========================== test session starts ============================
|
||||
platform darwin -- Python 2.7.1 -- pytest-2.2.1
|
||||
============================= test session starts ==============================
|
||||
platform darwin -- Python 2.7.1 -- pytest-2.2.2.dev3
|
||||
collecting ... collected 4 items
|
||||
|
||||
test_server.py .
|
||||
|
||||
=================== 3 tests deselected by '-ksend_http' ====================
|
||||
================== 1 passed, 3 deselected in 0.02 seconds ==================
|
||||
===================== 3 tests deselected by '-ksend_http' ======================
|
||||
==================== 1 passed, 3 deselected in 0.06 seconds ====================
|
||||
|
||||
And you can also run all tests except the ones that match the keyword::
|
||||
|
||||
$ py.test -k-send_http
|
||||
=========================== test session starts ============================
|
||||
platform darwin -- Python 2.7.1 -- pytest-2.2.1
|
||||
============================= test session starts ==============================
|
||||
platform darwin -- Python 2.7.1 -- pytest-2.2.2.dev3
|
||||
collecting ... collected 4 items
|
||||
|
||||
test_mark_classlevel.py ..
|
||||
test_server.py .
|
||||
|
||||
=================== 1 tests deselected by '-k-send_http' ===================
|
||||
================== 3 passed, 1 deselected in 0.03 seconds ==================
|
||||
===================== 1 tests deselected by '-k-send_http' =====================
|
||||
==================== 3 passed, 1 deselected in 0.05 seconds ====================
|
||||
|
||||
Or to only select the class::
|
||||
|
||||
$ py.test -kTestClass
|
||||
=========================== test session starts ============================
|
||||
platform darwin -- Python 2.7.1 -- pytest-2.2.1
|
||||
============================= test session starts ==============================
|
||||
platform darwin -- Python 2.7.1 -- pytest-2.2.2.dev3
|
||||
collecting ... collected 4 items
|
||||
|
||||
test_mark_classlevel.py ..
|
||||
|
||||
=================== 2 tests deselected by '-kTestClass' ====================
|
||||
================== 2 passed, 2 deselected in 0.02 seconds ==================
|
||||
===================== 2 tests deselected by '-kTestClass' ======================
|
||||
==================== 2 passed, 2 deselected in 0.04 seconds ====================
|
||||
|
||||
.. _`adding a custom marker from a plugin`:
|
||||
|
||||
|
@ -221,24 +222,24 @@ and an example invocations specifying a different environment than what
|
|||
the test needs::
|
||||
|
||||
$ py.test -E stage2
|
||||
=========================== test session starts ============================
|
||||
platform darwin -- Python 2.7.1 -- pytest-2.2.1
|
||||
============================= test session starts ==============================
|
||||
platform darwin -- Python 2.7.1 -- pytest-2.2.2.dev3
|
||||
collecting ... collected 1 items
|
||||
|
||||
test_someenv.py s
|
||||
|
||||
======================== 1 skipped in 0.02 seconds =========================
|
||||
========================== 1 skipped in 0.03 seconds ===========================
|
||||
|
||||
and here is one that specifies exactly the environment needed::
|
||||
|
||||
$ py.test -E stage1
|
||||
=========================== test session starts ============================
|
||||
platform darwin -- Python 2.7.1 -- pytest-2.2.1
|
||||
============================= test session starts ==============================
|
||||
platform darwin -- Python 2.7.1 -- pytest-2.2.2.dev3
|
||||
collecting ... collected 1 items
|
||||
|
||||
test_someenv.py .
|
||||
|
||||
========================= 1 passed in 0.01 seconds =========================
|
||||
=========================== 1 passed in 0.03 seconds ===========================
|
||||
|
||||
The ``--markers`` option always gives you a list of available markers::
|
||||
|
||||
|
@ -254,4 +255,43 @@ The ``--markers`` option always gives you a list of available markers::
|
|||
@pytest.mark.tryfirst: mark a hook implementation function such that the plugin machinery will try to call it first/as early as possible.
|
||||
|
||||
@pytest.mark.trylast: mark a hook implementation function such that the plugin machinery will try to call it last/as late as possible.
|
||||
|
||||
|
||||
Reading markers which were set from multiple places
|
||||
----------------------------------------------------
|
||||
|
||||
.. versionadded: 2.2.2
|
||||
|
||||
If you are heavily using markers in your test suite you may encounter the case where a marker is applied several times to a test function. From plugin
|
||||
code you can read over all such settings. Example::
|
||||
|
||||
# content of test_mark_three_times.py
|
||||
import pytest
|
||||
pytestmark = pytest.mark.glob("module", x=1)
|
||||
|
||||
@pytest.mark.glob("class", x=2)
|
||||
class TestClass:
|
||||
@pytest.mark.glob("function", x=3)
|
||||
def test_something(self):
|
||||
pass
|
||||
|
||||
Here we have the marker "glob" applied three times to the same
|
||||
test function. From a conftest file we can read it like this::
|
||||
|
||||
# content of conftest.py
|
||||
|
||||
def pytest_runtest_setup(item):
|
||||
g = getattr(item.obj, 'glob', None)
|
||||
if g is not None:
|
||||
for info in g:
|
||||
print ("glob args=%s kwargs=%s" %(info.args, info.kwargs))
|
||||
|
||||
Let's run this without capturing output and see what we get::
|
||||
|
||||
$ py.test -q -s
|
||||
collecting ... collected 2 items
|
||||
..
|
||||
2 passed in 0.04 seconds
|
||||
glob args=('function',) kwargs={'x': 3}
|
||||
glob args=('module',) kwargs={'x': 1}
|
||||
glob args=('class',) kwargs={'x': 2}
|
||||
|
|
|
@ -230,6 +230,14 @@ class TestFunctional:
|
|||
assert marker.args == ("pos0", "pos1")
|
||||
assert marker.kwargs == {'x': 3, 'y': 2, 'z': 4}
|
||||
|
||||
# test the new __iter__ interface
|
||||
l = list(marker)
|
||||
assert len(l) == 3
|
||||
assert l[0].args == ("pos0",)
|
||||
pytest.xfail(reason="needs reordering of parametrize transfermarks")
|
||||
assert l[1].args == ()
|
||||
assert l[2].args == ("pos1", )
|
||||
|
||||
def test_mark_other(self, testdir):
|
||||
pytest.raises(TypeError, '''
|
||||
testdir.getitem("""
|
||||
|
@ -259,6 +267,23 @@ class TestFunctional:
|
|||
"keyword: *hello*"
|
||||
])
|
||||
|
||||
def test_merging_markers_two_functions(self, testdir):
|
||||
p = testdir.makepyfile("""
|
||||
import pytest
|
||||
@pytest.mark.hello("pos1", z=4)
|
||||
@pytest.mark.hello("pos0", z=3)
|
||||
def test_func(self):
|
||||
pass
|
||||
""")
|
||||
items, rec = testdir.inline_genitems(p)
|
||||
item, = items
|
||||
keywords = item.keywords
|
||||
marker = keywords['hello']
|
||||
l = list(marker)
|
||||
assert len(l) == 2
|
||||
assert l[0].args == ("pos0",)
|
||||
assert l[1].args == ("pos1",)
|
||||
|
||||
|
||||
class TestKeywordSelection:
|
||||
def test_select_simple(self, testdir):
|
||||
|
|
Loading…
Reference in New Issue