parent
eca93db05b
commit
9fbd67dd4b
1
AUTHORS
1
AUTHORS
|
@ -225,6 +225,7 @@ Marcin Bachry
|
||||||
Marco Gorelli
|
Marco Gorelli
|
||||||
Mark Abramowitz
|
Mark Abramowitz
|
||||||
Mark Dickinson
|
Mark Dickinson
|
||||||
|
Marko Pacak
|
||||||
Markus Unterwaditzer
|
Markus Unterwaditzer
|
||||||
Martijn Faassen
|
Martijn Faassen
|
||||||
Martin Altmayer
|
Martin Altmayer
|
||||||
|
|
|
@ -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.
|
|
@ -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`_.
|
* In those directories, search for ``test_*.py`` or ``*_test.py`` files, imported by their `test package name`_.
|
||||||
* From those files, collect test items:
|
* From those files, collect test items:
|
||||||
|
|
||||||
* ``test`` prefixed test functions or methods outside of class
|
* ``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 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`.
|
For examples of how to customize your test discovery :doc:`/example/pythoncollection`.
|
||||||
|
|
||||||
|
|
|
@ -403,8 +403,8 @@ class PyCollector(PyobjMixin, nodes.Collector):
|
||||||
|
|
||||||
def istestfunction(self, obj: object, name: str) -> bool:
|
def istestfunction(self, obj: object, name: str) -> bool:
|
||||||
if self.funcnamefilter(name) or self.isnosetest(obj):
|
if self.funcnamefilter(name) or self.isnosetest(obj):
|
||||||
if isinstance(obj, staticmethod):
|
if isinstance(obj, (staticmethod, classmethod)):
|
||||||
# staticmethods need to be unwrapped.
|
# staticmethods and classmethods need to be unwrapped.
|
||||||
obj = safe_getattr(obj, "__func__", False)
|
obj = safe_getattr(obj, "__func__", False)
|
||||||
return callable(obj) and fixtures.getfixturemarker(obj) is None
|
return callable(obj) and fixtures.getfixturemarker(obj) is None
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -416,7 +416,7 @@ def test_function_instance(pytester: Pytester) -> None:
|
||||||
def test_static(): pass
|
def test_static(): pass
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
assert len(items) == 3
|
assert len(items) == 4
|
||||||
assert isinstance(items[0], Function)
|
assert isinstance(items[0], Function)
|
||||||
assert items[0].name == "test_func"
|
assert items[0].name == "test_func"
|
||||||
assert items[0].instance is None
|
assert items[0].instance is None
|
||||||
|
@ -424,6 +424,6 @@ def test_function_instance(pytester: Pytester) -> None:
|
||||||
assert items[1].name == "test_method"
|
assert items[1].name == "test_method"
|
||||||
assert items[1].instance is not None
|
assert items[1].instance is not None
|
||||||
assert items[1].instance.__class__.__name__ == "TestIt"
|
assert items[1].instance.__class__.__name__ == "TestIt"
|
||||||
assert isinstance(items[2], Function)
|
assert isinstance(items[3], Function)
|
||||||
assert items[2].name == "test_static"
|
assert items[3].name == "test_static"
|
||||||
assert items[2].instance is None
|
assert items[3].instance is None
|
||||||
|
|
|
@ -735,6 +735,20 @@ class Test_genitems:
|
||||||
assert s.endswith("test_example_items1.testone")
|
assert s.endswith("test_example_items1.testone")
|
||||||
print(s)
|
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:
|
def test_class_and_functions_discovery_using_glob(self, pytester: Pytester) -> None:
|
||||||
"""Test that Python_classes and Python_functions config options work
|
"""Test that Python_classes and Python_functions config options work
|
||||||
as prefixes and glob-like patterns (#600)."""
|
as prefixes and glob-like patterns (#600)."""
|
||||||
|
|
Loading…
Reference in New Issue