introduce an option that avoids discovery of classes other than unittest.TestCase in modules
importing unittest.
This commit is contained in:
parent
707775dcfa
commit
d0ac4135a2
|
@ -403,7 +403,11 @@ def main(args=None, plugins=None):
|
||||||
if args is None:
|
if args is None:
|
||||||
args = sys.argv[1:]
|
args = sys.argv[1:]
|
||||||
elif not isinstance(args, (tuple, list)):
|
elif not isinstance(args, (tuple, list)):
|
||||||
args = py.std.shlex.split(str(args))
|
if isinstance(args, py.path.local):
|
||||||
|
args = str(args)
|
||||||
|
if not isinstance(args, str):
|
||||||
|
raise ValueError("not a string or argument list: %r" % (args,))
|
||||||
|
args = py.std.shlex.split(args)
|
||||||
if _preinit:
|
if _preinit:
|
||||||
_pluginmanager = _preinit.pop(0)
|
_pluginmanager = _preinit.pop(0)
|
||||||
else: # subsequent calls to main will create a fresh instance
|
else: # subsequent calls to main will create a fresh instance
|
||||||
|
|
|
@ -3,6 +3,7 @@ support for presented detailed information in failing assertions.
|
||||||
"""
|
"""
|
||||||
import py
|
import py
|
||||||
import sys
|
import sys
|
||||||
|
from pytest.plugin.monkeypatch import monkeypatch
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
group = parser.getgroup("debugconfig")
|
group = parser.getgroup("debugconfig")
|
||||||
|
@ -15,25 +16,21 @@ def pytest_configure(config):
|
||||||
# py._code._assertionnew to detect this plugin was loaded and in
|
# py._code._assertionnew to detect this plugin was loaded and in
|
||||||
# turn call the hooks defined here as part of the
|
# turn call the hooks defined here as part of the
|
||||||
# DebugInterpreter.
|
# DebugInterpreter.
|
||||||
|
config._monkeypatch = m = monkeypatch()
|
||||||
if not config.getvalue("noassert") and not config.getvalue("nomagic"):
|
if not config.getvalue("noassert") and not config.getvalue("nomagic"):
|
||||||
warn_about_missing_assertion()
|
warn_about_missing_assertion()
|
||||||
config._oldassertion = py.builtin.builtins.AssertionError
|
|
||||||
config._oldbinrepr = py.code._reprcompare
|
|
||||||
py.builtin.builtins.AssertionError = py.code._AssertionError
|
|
||||||
def callbinrepr(op, left, right):
|
def callbinrepr(op, left, right):
|
||||||
hook_result = config.hook.pytest_assertrepr_compare(
|
hook_result = config.hook.pytest_assertrepr_compare(
|
||||||
config=config, op=op, left=left, right=right)
|
config=config, op=op, left=left, right=right)
|
||||||
for new_expl in hook_result:
|
for new_expl in hook_result:
|
||||||
if new_expl:
|
if new_expl:
|
||||||
return '\n~'.join(new_expl)
|
return '\n~'.join(new_expl)
|
||||||
py.code._reprcompare = callbinrepr
|
m.setattr(py.builtin.builtins,
|
||||||
|
'AssertionError', py.code._AssertionError)
|
||||||
|
m.setattr(py.code, '_reprcompare', callbinrepr)
|
||||||
|
|
||||||
def pytest_unconfigure(config):
|
def pytest_unconfigure(config):
|
||||||
if hasattr(config, '_oldassertion'):
|
config._monkeypatch.undo()
|
||||||
py.builtin.builtins.AssertionError = config._oldassertion
|
|
||||||
py.code._reprcompare = config._oldbinrepr
|
|
||||||
del config._oldassertion
|
|
||||||
del config._oldbinrepr
|
|
||||||
|
|
||||||
def warn_about_missing_assertion():
|
def warn_about_missing_assertion():
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -59,6 +59,8 @@ def pytest_pycollect_makeitem(__multicall__, collector, name, obj):
|
||||||
if res is not None:
|
if res is not None:
|
||||||
return res
|
return res
|
||||||
if collector._istestclasscandidate(name, obj):
|
if collector._istestclasscandidate(name, obj):
|
||||||
|
if hasattr(collector.obj, 'unittest'):
|
||||||
|
return # we assume it's a mixin class for a TestCase derived one
|
||||||
return Class(name, parent=collector)
|
return Class(name, parent=collector)
|
||||||
elif collector.funcnamefilter(name) and hasattr(obj, '__call__'):
|
elif collector.funcnamefilter(name) and hasattr(obj, '__call__'):
|
||||||
if is_generator(obj):
|
if is_generator(obj):
|
||||||
|
@ -124,6 +126,7 @@ class PyobjMixin(object):
|
||||||
return self._fslineno
|
return self._fslineno
|
||||||
|
|
||||||
def reportinfo(self):
|
def reportinfo(self):
|
||||||
|
# XXX caching?
|
||||||
obj = self.obj
|
obj = self.obj
|
||||||
if hasattr(obj, 'compat_co_firstlineno'):
|
if hasattr(obj, 'compat_co_firstlineno'):
|
||||||
# nose compatibility
|
# nose compatibility
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
""" support discovery and running of traditional "unittest.py" style tests. """
|
""" discovery and running of std-library "unittest" style tests. """
|
||||||
import py
|
import py
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
def pytest_pycollect_makeitem(collector, name, obj):
|
def pytest_pycollect_makeitem(collector, name, obj):
|
||||||
if 'unittest' not in sys.modules:
|
unittest = sys.modules.get('unittest')
|
||||||
return # nobody derived unittest.TestCase
|
if unittest is None:
|
||||||
|
return # nobody can have derived unittest.TestCase
|
||||||
try:
|
try:
|
||||||
isunit = issubclass(obj, py.std.unittest.TestCase)
|
isunit = issubclass(obj, unittest.TestCase)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
raise
|
raise
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
|
@ -294,6 +294,7 @@ class TestInvocationVariants:
|
||||||
assert not retcode
|
assert not retcode
|
||||||
out, err = capsys.readouterr()
|
out, err = capsys.readouterr()
|
||||||
assert "--help" in out
|
assert "--help" in out
|
||||||
|
pytest.raises(ValueError, lambda: pytest.main(retcode))
|
||||||
|
|
||||||
def test_invoke_with_path(self, testdir, capsys):
|
def test_invoke_with_path(self, testdir, capsys):
|
||||||
retcode = testdir.pytestmain(testdir.tmpdir)
|
retcode = testdir.pytestmain(testdir.tmpdir)
|
||||||
|
@ -330,3 +331,18 @@ class TestInvocationVariants:
|
||||||
result.stderr.fnmatch_lines([
|
result.stderr.fnmatch_lines([
|
||||||
"ERROR*file*or*package*not*found*",
|
"ERROR*file*or*package*not*found*",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def test_noclass_discovery_if_not_testcase(self, testdir):
|
||||||
|
testpath = testdir.makepyfile("""
|
||||||
|
import unittest
|
||||||
|
import py
|
||||||
|
class TestHello(object):
|
||||||
|
def test_hello(self):
|
||||||
|
assert self.attr
|
||||||
|
|
||||||
|
class RealTest(TestHello, unittest.TestCase):
|
||||||
|
attr = 42
|
||||||
|
""")
|
||||||
|
reprec = testdir.inline_run(testpath)
|
||||||
|
reprec.assertoutcome(passed=1)
|
||||||
|
|
|
@ -161,6 +161,15 @@ def test_functional(testdir):
|
||||||
result = testdir.runpytest("--no-assert")
|
result = testdir.runpytest("--no-assert")
|
||||||
assert "3 == 4" not in result.stdout.str()
|
assert "3 == 4" not in result.stdout.str()
|
||||||
|
|
||||||
|
def test_AssertionErrorIdentity(testdir):
|
||||||
|
testdir.makepyfile("""
|
||||||
|
def test_hello():
|
||||||
|
import exceptions
|
||||||
|
assert AssertionError is exceptions.AssertionError
|
||||||
|
""")
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.stdout.fnmatch_lines(["*1 passed*"])
|
||||||
|
|
||||||
def test_triple_quoted_string_issue113(testdir):
|
def test_triple_quoted_string_issue113(testdir):
|
||||||
testdir.makepyfile("""
|
testdir.makepyfile("""
|
||||||
def test_hello():
|
def test_hello():
|
||||||
|
|
Loading…
Reference in New Issue