introduce an option that avoids discovery of classes other than unittest.TestCase in modules

importing unittest.
This commit is contained in:
holger krekel 2010-11-06 23:45:48 +01:00
parent 707775dcfa
commit d0ac4135a2
7 changed files with 46 additions and 15 deletions

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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():

View File

@ -52,5 +52,6 @@ commands=
[pytest] [pytest]
minversion=2.0 minversion=2.0
plugins=pytester plugins=pytester
addargs=-rfx addopts=-rfx --pyargs
rsyncdirs=pytest testing rsyncdirs=pytest testing