From 24db492f53a7391c2bbc660adb0c44f072dfca58 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Tue, 11 Mar 2014 22:10:18 +0100 Subject: [PATCH] warn if instances are callable and have a test name --- _pytest/python.py | 21 +++++++++++++-------- _pytest/terminal.py | 2 +- testing/python/collect.py | 25 ++++++++++++++++++------- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/_pytest/python.py b/_pytest/python.py index a882dec70..89be2598a 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -11,7 +11,8 @@ cutdir = py.path.local(_pytest.__file__).dirpath() NoneType = type(None) NOTSET = object() - +isfunction = inspect.isfunction +isclass = inspect.isclass callable = py.builtin.callable def getfslineno(obj): @@ -44,7 +45,7 @@ class FixtureFunctionMarker: self.ids = ids def __call__(self, function): - if inspect.isclass(function): + if isclass(function): raise ValueError( "class fixtures not supported (may be in the future)") function._pytestfixturefunction = self @@ -213,14 +214,19 @@ def pytest_pycollect_makeitem(__multicall__, collector, name, obj): res = __multicall__.execute() if res is not None: return res - if inspect.isclass(obj): + if isclass(obj): #if hasattr(collector.obj, 'unittest'): # return # we assume it's a mixin class for a TestCase derived one if collector.classnamefilter(name): Class = collector._getcustomclass("Class") 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: + if not isfunction(obj): + collector.warn(code="C2", message= + "cannot collect %r because it is not a function." + % name, ) + return if is_generator(obj): return Generator(name, parent=collector) else: @@ -498,10 +504,9 @@ class Class(PyCollector): """ Collector for test methods. """ def collect(self): if hasinit(self.obj): - pytest.skip("class %s.%s with __init__ won't get collected" % ( - self.obj.__module__, - self.obj.__name__, - )) + self.warn("C1", "cannot collect test class %r because it has a " + "__init__ constructor" % self.obj.__name__) + return [] return [self._getcustomclass("Instance")(name="()", parent=self)] def setup(self): diff --git a/_pytest/terminal.py b/_pytest/terminal.py index f85cbeca1..4e73e40df 100644 --- a/_pytest/terminal.py +++ b/_pytest/terminal.py @@ -15,7 +15,7 @@ def pytest_addoption(parser): group._addoption('-r', action="store", dest="reportchars", default=None, metavar="chars", 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', action="store_true", dest="showlocals", default=False, help="show locals in tracebacks (disabled by default).") diff --git a/testing/python/collect.py b/testing/python/collect.py index 381f68797..1e911cf19 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -33,8 +33,8 @@ class TestModule: pytest.raises(ImportError, lambda: modcol.obj) class TestClass: - def test_class_with_init_skip_collect(self, testdir): - modcol = testdir.getmodulecol(""" + def test_class_with_init_warning(self, testdir): + testdir.makepyfile(""" class TestClass1: def __init__(self): pass @@ -42,11 +42,11 @@ class TestClass: def __init__(self): pass """) - l = modcol.collect() - assert len(l) == 2 - - for classcol in l: - pytest.raises(pytest.skip.Exception, classcol.collect) + result = testdir.runpytest("-rw") + result.stdout.fnmatch_lines(""" + WC1*test_class_with_init_warning.py*__init__* + *2 warnings* + """) def test_class_subclassobject(self, testdir): testdir.getmodulecol(""" @@ -276,6 +276,17 @@ class TestFunction: assert isinstance(modcol, pytest.Module) 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): from _pytest.python import FixtureManager config = testdir.parseconfigure()