Make sure marks in subclasses don't change marks in superclasses
Fix #842
This commit is contained in:
parent
94cdec2cfe
commit
aa25fb05a9
|
@ -1,6 +1,10 @@
|
||||||
2.7.3 (compared to 2.7.2)
|
2.7.3 (compared to 2.7.2)
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
- fix issue842: applying markers in classes no longer propagate this markers
|
||||||
|
to superclasses which also have markers.
|
||||||
|
Thanks xmo-odoo for the report and Bruno Oliveira for the PR.
|
||||||
|
|
||||||
- preserve warning functions after call to pytest.deprecated_call. Thanks
|
- preserve warning functions after call to pytest.deprecated_call. Thanks
|
||||||
Pieter Mulder for PR.
|
Pieter Mulder for PR.
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
""" generic mechanism for marking and selecting python functions. """
|
""" generic mechanism for marking and selecting python functions. """
|
||||||
|
import inspect
|
||||||
import py
|
import py
|
||||||
|
|
||||||
|
|
||||||
|
@ -253,15 +254,17 @@ class MarkDecorator:
|
||||||
otherwise add *args/**kwargs in-place to mark information. """
|
otherwise add *args/**kwargs in-place to mark information. """
|
||||||
if args and not kwargs:
|
if args and not kwargs:
|
||||||
func = args[0]
|
func = args[0]
|
||||||
if len(args) == 1 and (istestfunc(func) or
|
is_class = inspect.isclass(func)
|
||||||
hasattr(func, '__bases__')):
|
if len(args) == 1 and (istestfunc(func) or is_class):
|
||||||
if hasattr(func, '__bases__'):
|
if is_class:
|
||||||
if hasattr(func, 'pytestmark'):
|
if hasattr(func, 'pytestmark'):
|
||||||
l = func.pytestmark
|
mark_list = func.pytestmark
|
||||||
if not isinstance(l, list):
|
if not isinstance(mark_list, list):
|
||||||
func.pytestmark = [l, self]
|
mark_list = [mark_list]
|
||||||
else:
|
# always work on a copy to avoid updating pytestmark
|
||||||
l.append(self)
|
# from a superclass by accident
|
||||||
|
mark_list = mark_list + [self]
|
||||||
|
func.pytestmark = mark_list
|
||||||
else:
|
else:
|
||||||
func.pytestmark = [self]
|
func.pytestmark = [self]
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -369,6 +369,45 @@ class TestFunctional:
|
||||||
print (item, item.keywords)
|
print (item, item.keywords)
|
||||||
assert 'a' in item.keywords
|
assert 'a' in item.keywords
|
||||||
|
|
||||||
|
def test_mark_decorator_subclass_does_not_propagate_to_base(self, testdir):
|
||||||
|
p = testdir.makepyfile("""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.mark.a
|
||||||
|
class Base: pass
|
||||||
|
|
||||||
|
@pytest.mark.b
|
||||||
|
class Test1(Base):
|
||||||
|
def test_foo(self): pass
|
||||||
|
|
||||||
|
class Test2(Base):
|
||||||
|
def test_bar(self): pass
|
||||||
|
""")
|
||||||
|
items, rec = testdir.inline_genitems(p)
|
||||||
|
self.assert_markers(items, test_foo=('a', 'b'), test_bar=('a',))
|
||||||
|
|
||||||
|
def test_mark_decorator_baseclasses_merged(self, testdir):
|
||||||
|
p = testdir.makepyfile("""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.mark.a
|
||||||
|
class Base: pass
|
||||||
|
|
||||||
|
@pytest.mark.b
|
||||||
|
class Base2(Base): pass
|
||||||
|
|
||||||
|
@pytest.mark.c
|
||||||
|
class Test1(Base2):
|
||||||
|
def test_foo(self): pass
|
||||||
|
|
||||||
|
class Test2(Base2):
|
||||||
|
@pytest.mark.d
|
||||||
|
def test_bar(self): pass
|
||||||
|
""")
|
||||||
|
items, rec = testdir.inline_genitems(p)
|
||||||
|
self.assert_markers(items, test_foo=('a', 'b', 'c'),
|
||||||
|
test_bar=('a', 'b', 'd'))
|
||||||
|
|
||||||
def test_mark_with_wrong_marker(self, testdir):
|
def test_mark_with_wrong_marker(self, testdir):
|
||||||
reprec = testdir.inline_runsource("""
|
reprec = testdir.inline_runsource("""
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -477,6 +516,22 @@ class TestFunctional:
|
||||||
reprec = testdir.inline_run("-m", "mark1")
|
reprec = testdir.inline_run("-m", "mark1")
|
||||||
reprec.assertoutcome(passed=1)
|
reprec.assertoutcome(passed=1)
|
||||||
|
|
||||||
|
def assert_markers(self, items, **expected):
|
||||||
|
"""assert that given items have expected marker names applied to them.
|
||||||
|
expected should be a dict of (item name -> seq of expected marker names)
|
||||||
|
|
||||||
|
.. note:: this could be moved to ``testdir`` if proven to be useful
|
||||||
|
to other modules.
|
||||||
|
"""
|
||||||
|
from _pytest.mark import MarkInfo
|
||||||
|
items = dict((x.name, x) for x in items)
|
||||||
|
for name, expected_markers in expected.items():
|
||||||
|
markers = items[name].keywords._markers
|
||||||
|
marker_names = set([name for (name, v) in markers.items()
|
||||||
|
if isinstance(v, MarkInfo)])
|
||||||
|
assert marker_names == set(expected_markers)
|
||||||
|
|
||||||
|
|
||||||
class TestKeywordSelection:
|
class TestKeywordSelection:
|
||||||
def test_select_simple(self, testdir):
|
def test_select_simple(self, testdir):
|
||||||
file_test = testdir.makepyfile("""
|
file_test = testdir.makepyfile("""
|
||||||
|
|
Loading…
Reference in New Issue