warn if instances are callable and have a test name
This commit is contained in:
parent
1b387bea62
commit
24db492f53
|
@ -11,7 +11,8 @@ cutdir = py.path.local(_pytest.__file__).dirpath()
|
||||||
|
|
||||||
NoneType = type(None)
|
NoneType = type(None)
|
||||||
NOTSET = object()
|
NOTSET = object()
|
||||||
|
isfunction = inspect.isfunction
|
||||||
|
isclass = inspect.isclass
|
||||||
callable = py.builtin.callable
|
callable = py.builtin.callable
|
||||||
|
|
||||||
def getfslineno(obj):
|
def getfslineno(obj):
|
||||||
|
@ -44,7 +45,7 @@ class FixtureFunctionMarker:
|
||||||
self.ids = ids
|
self.ids = ids
|
||||||
|
|
||||||
def __call__(self, function):
|
def __call__(self, function):
|
||||||
if inspect.isclass(function):
|
if isclass(function):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"class fixtures not supported (may be in the future)")
|
"class fixtures not supported (may be in the future)")
|
||||||
function._pytestfixturefunction = self
|
function._pytestfixturefunction = self
|
||||||
|
@ -213,14 +214,19 @@ def pytest_pycollect_makeitem(__multicall__, collector, name, obj):
|
||||||
res = __multicall__.execute()
|
res = __multicall__.execute()
|
||||||
if res is not None:
|
if res is not None:
|
||||||
return res
|
return res
|
||||||
if inspect.isclass(obj):
|
if isclass(obj):
|
||||||
#if hasattr(collector.obj, 'unittest'):
|
#if hasattr(collector.obj, 'unittest'):
|
||||||
# return # we assume it's a mixin class for a TestCase derived one
|
# return # we assume it's a mixin class for a TestCase derived one
|
||||||
if collector.classnamefilter(name):
|
if collector.classnamefilter(name):
|
||||||
Class = collector._getcustomclass("Class")
|
Class = collector._getcustomclass("Class")
|
||||||
return Class(name, parent=collector)
|
return Class(name, parent=collector)
|
||||||
elif collector.funcnamefilter(name) and hasattr(obj, '__call__') and \
|
elif collector.funcnamefilter(name) and hasattr(obj, "__call__") and \
|
||||||
getfixturemarker(obj) is None:
|
getfixturemarker(obj) is None:
|
||||||
|
if not isfunction(obj):
|
||||||
|
collector.warn(code="C2", message=
|
||||||
|
"cannot collect %r because it is not a function."
|
||||||
|
% name, )
|
||||||
|
return
|
||||||
if is_generator(obj):
|
if is_generator(obj):
|
||||||
return Generator(name, parent=collector)
|
return Generator(name, parent=collector)
|
||||||
else:
|
else:
|
||||||
|
@ -498,10 +504,9 @@ class Class(PyCollector):
|
||||||
""" Collector for test methods. """
|
""" Collector for test methods. """
|
||||||
def collect(self):
|
def collect(self):
|
||||||
if hasinit(self.obj):
|
if hasinit(self.obj):
|
||||||
pytest.skip("class %s.%s with __init__ won't get collected" % (
|
self.warn("C1", "cannot collect test class %r because it has a "
|
||||||
self.obj.__module__,
|
"__init__ constructor" % self.obj.__name__)
|
||||||
self.obj.__name__,
|
return []
|
||||||
))
|
|
||||||
return [self._getcustomclass("Instance")(name="()", parent=self)]
|
return [self._getcustomclass("Instance")(name="()", parent=self)]
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
|
|
|
@ -15,7 +15,7 @@ def pytest_addoption(parser):
|
||||||
group._addoption('-r',
|
group._addoption('-r',
|
||||||
action="store", dest="reportchars", default=None, metavar="chars",
|
action="store", dest="reportchars", default=None, metavar="chars",
|
||||||
help="show extra test summary info as specified by chars (f)ailed, "
|
help="show extra test summary info as specified by chars (f)ailed, "
|
||||||
"(E)error, (s)skipped, (x)failed, (X)passed.")
|
"(E)error, (s)skipped, (x)failed, (X)passed (w)warnings.")
|
||||||
group._addoption('-l', '--showlocals',
|
group._addoption('-l', '--showlocals',
|
||||||
action="store_true", dest="showlocals", default=False,
|
action="store_true", dest="showlocals", default=False,
|
||||||
help="show locals in tracebacks (disabled by default).")
|
help="show locals in tracebacks (disabled by default).")
|
||||||
|
|
|
@ -33,8 +33,8 @@ class TestModule:
|
||||||
pytest.raises(ImportError, lambda: modcol.obj)
|
pytest.raises(ImportError, lambda: modcol.obj)
|
||||||
|
|
||||||
class TestClass:
|
class TestClass:
|
||||||
def test_class_with_init_skip_collect(self, testdir):
|
def test_class_with_init_warning(self, testdir):
|
||||||
modcol = testdir.getmodulecol("""
|
testdir.makepyfile("""
|
||||||
class TestClass1:
|
class TestClass1:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
@ -42,11 +42,11 @@ class TestClass:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
""")
|
""")
|
||||||
l = modcol.collect()
|
result = testdir.runpytest("-rw")
|
||||||
assert len(l) == 2
|
result.stdout.fnmatch_lines("""
|
||||||
|
WC1*test_class_with_init_warning.py*__init__*
|
||||||
for classcol in l:
|
*2 warnings*
|
||||||
pytest.raises(pytest.skip.Exception, classcol.collect)
|
""")
|
||||||
|
|
||||||
def test_class_subclassobject(self, testdir):
|
def test_class_subclassobject(self, testdir):
|
||||||
testdir.getmodulecol("""
|
testdir.getmodulecol("""
|
||||||
|
@ -276,6 +276,17 @@ class TestFunction:
|
||||||
assert isinstance(modcol, pytest.Module)
|
assert isinstance(modcol, pytest.Module)
|
||||||
assert hasattr(modcol.obj, 'test_func')
|
assert hasattr(modcol.obj, 'test_func')
|
||||||
|
|
||||||
|
def test_function_as_object_instance_ignored(self, testdir):
|
||||||
|
item = testdir.makepyfile("""
|
||||||
|
class A:
|
||||||
|
def __call__(self, tmpdir):
|
||||||
|
0/0
|
||||||
|
|
||||||
|
test_a = A()
|
||||||
|
""")
|
||||||
|
reprec = testdir.inline_run()
|
||||||
|
reprec.assertoutcome()
|
||||||
|
|
||||||
def test_function_equality(self, testdir, tmpdir):
|
def test_function_equality(self, testdir, tmpdir):
|
||||||
from _pytest.python import FixtureManager
|
from _pytest.python import FixtureManager
|
||||||
config = testdir.parseconfigure()
|
config = testdir.parseconfigure()
|
||||||
|
|
Loading…
Reference in New Issue