Skip to content

Commit

Permalink
Class methods can now be discovered as tests (#10552)
Browse files Browse the repository at this point in the history
Fix #10525
  • Loading branch information
markopacak committed Dec 2, 2022
1 parent eca93db commit 9fbd67d
Show file tree
Hide file tree
Showing 6 changed files with 24 additions and 8 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ Marcin Bachry
Marco Gorelli
Mark Abramowitz
Mark Dickinson
Marko Pacak
Markus Unterwaditzer
Martijn Faassen
Martin Altmayer
Expand Down
1 change: 1 addition & 0 deletions changelog/10525.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Test methods decorated with ``@classmethod`` can now be discovered as tests, following the same rules as normal methods. This fills the gap that static methods were discoverable as tests but not class methods.
4 changes: 2 additions & 2 deletions doc/en/explanation/goodpractices.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ Conventions for Python test discovery
* In those directories, search for ``test_*.py`` or ``*_test.py`` files, imported by their `test package name`_.
* From those files, collect test items:

* ``test`` prefixed test functions or methods outside of class
* ``test`` prefixed test functions or methods inside ``Test`` prefixed test classes (without an ``__init__`` method)
* ``test`` prefixed test functions or methods outside of class.
* ``test`` prefixed test functions or methods inside ``Test`` prefixed test classes (without an ``__init__`` method). Methods decorated with ``@staticmethod`` and ``@classmethods`` are also considered.

For examples of how to customize your test discovery :doc:`/example/pythoncollection`.

Expand Down
4 changes: 2 additions & 2 deletions src/_pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,8 +403,8 @@ def classnamefilter(self, name: str) -> bool:

def istestfunction(self, obj: object, name: str) -> bool:
if self.funcnamefilter(name) or self.isnosetest(obj):
if isinstance(obj, staticmethod):
# staticmethods need to be unwrapped.
if isinstance(obj, (staticmethod, classmethod)):
# staticmethods and classmethods need to be unwrapped.
obj = safe_getattr(obj, "__func__", False)
return callable(obj) and fixtures.getfixturemarker(obj) is None
else:
Expand Down
8 changes: 4 additions & 4 deletions testing/python/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,14 +416,14 @@ def test_class(cls): pass
def test_static(): pass
"""
)
assert len(items) == 3
assert len(items) == 4
assert isinstance(items[0], Function)
assert items[0].name == "test_func"
assert items[0].instance is None
assert isinstance(items[1], Function)
assert items[1].name == "test_method"
assert items[1].instance is not None
assert items[1].instance.__class__.__name__ == "TestIt"
assert isinstance(items[2], Function)
assert items[2].name == "test_static"
assert items[2].instance is None
assert isinstance(items[3], Function)
assert items[3].name == "test_static"
assert items[3].instance is None
14 changes: 14 additions & 0 deletions testing/test_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,20 @@ def testmethod_two(self, arg0):
assert s.endswith("test_example_items1.testone")
print(s)

def test_classmethod_is_discovered(self, pytester: Pytester) -> None:
"""Test that classmethods are discovered"""
p = pytester.makepyfile(
"""
class TestCase:
@classmethod
def test_classmethod(cls) -> None:
pass
"""
)
items, reprec = pytester.inline_genitems(p)
ids = [x.getmodpath() for x in items] # type: ignore[attr-defined]
assert ids == ["TestCase.test_classmethod"]

def test_class_and_functions_discovery_using_glob(self, pytester: Pytester) -> None:
"""Test that Python_classes and Python_functions config options work
as prefixes and glob-like patterns (#600)."""
Expand Down

0 comments on commit 9fbd67d

Please sign in to comment.