Skip to content

Commit d76fe38

Browse files
committed
pytest.mark in class marks methods defined in the class body only
1 parent 8f4f2c6 commit d76fe38

File tree

3 files changed

+51
-6
lines changed

3 files changed

+51
-6
lines changed

CHANGELOG

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
all directories that do not contain tests.
2727
Thanks to Adrian for idea (#694) and Bruno Oliveira for the PR.
2828

29+
- fix issue725: pytest.mark in class decorators will mark methods defined
30+
in the class body only, instead of propagating marks to the superclass'
31+
test methods.
32+
Thanks to foobarbazquux for the report and Bruno Oliveira for the PR.
33+
2934
- fix issue713: JUnit XML reports for doctest failures.
3035
Thanks Punyashloka Biswal.
3136

_pytest/python.py

+13-6
Original file line numberDiff line numberDiff line change
@@ -474,16 +474,23 @@ def __init__(self, argnames, names_closure, name2fixturedefs):
474474
def transfer_markers(funcobj, cls, mod):
475475
# XXX this should rather be code in the mark plugin or the mark
476476
# plugin should merge with the python plugin.
477-
for holder in (cls, mod):
477+
def transfer(holder):
478478
try:
479479
pytestmark = holder.pytestmark
480480
except AttributeError:
481-
continue
482-
if isinstance(pytestmark, list):
483-
for mark in pytestmark:
484-
mark(funcobj)
481+
pass
485482
else:
486-
pytestmark(funcobj)
483+
if isinstance(pytestmark, list):
484+
for mark in pytestmark:
485+
mark(funcobj)
486+
else:
487+
pytestmark(funcobj)
488+
489+
# transfer markers from class decorators only if the method is defined
490+
# in the class itself
491+
if cls is not None and funcobj.__name__ in cls.__dict__:
492+
transfer(cls)
493+
transfer(mod)
487494

488495
class Module(pytest.File, PyCollector):
489496
""" Collector for test classes and functions. """

testing/test_mark.py

+33
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,39 @@ def test_some(request):
477477
reprec = testdir.inline_run("-m", "mark1")
478478
reprec.assertoutcome(passed=1)
479479

480+
def test_class_makker_applies_to_its_own_methods_only(self, testdir):
481+
"""Check that markers applied using class decorators apply markers
482+
only to methods defined in the class itself but not to methods
483+
in super classes (#725).
484+
"""
485+
testdir.makepyfile("""
486+
import pytest
487+
488+
class Base:
489+
def test_base(self):
490+
pass
491+
492+
@pytest.mark.a
493+
class Test1(Base):
494+
def test_foo(self):
495+
pass
496+
497+
@pytest.mark.b
498+
class Test2(Base):
499+
def test_bar(self):
500+
pass
501+
""")
502+
result = testdir.runpytest('--collect-only', '-m', 'a')
503+
result.stdout.fnmatch_lines([
504+
'*test_foo*',
505+
'*3 deselected*'
506+
])
507+
result = testdir.runpytest('--collect-only', '-m', 'b')
508+
result.stdout.fnmatch_lines([
509+
'*test_bar*',
510+
'*3 deselected*'
511+
])
512+
480513
class TestKeywordSelection:
481514
def test_select_simple(self, testdir):
482515
file_test = testdir.makepyfile("""

0 commit comments

Comments
 (0)