diff options
author | Erik Rose <erik@mozilla.com> | 2011-12-18 01:01:21 -0800 |
---|---|---|
committer | Erik Rose <erik@mozilla.com> | 2011-12-18 15:30:19 -0800 |
commit | 28db0e5f14ece94865b59e4aeda3dea71afd9435 (patch) | |
tree | 0f4d48961487e4977969d779944190b058fa9b72 | |
parent | 8f923b3e241ea3ecb695050c51ae28769a23612a (diff) | |
download | nose-28db0e5f14ece94865b59e4aeda3dea71afd9435.tar.gz |
Define __unittest in scope of nose's assertion helpers to hide noisy stack frames. Closes #453.
I divided the tools into two buckets: trivial, which should not have their stack frames exposed in tracebacks; and nontrivial, which should. The tools module becomes a package, and everything stays backward-compatible.
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | CHANGELOG | 3 | ||||
-rw-r--r-- | nose/tools/__init__.py | 11 | ||||
-rw-r--r-- | nose/tools/nontrivial.py (renamed from nose/tools.py) | 52 | ||||
-rw-r--r-- | nose/tools/trivial.py | 52 | ||||
-rw-r--r-- | unit_tests/test_tools.py | 50 |
6 files changed, 104 insertions, 65 deletions
@@ -22,3 +22,4 @@ Takafumi Arakaki Peter Bengtsson Gary Donovan Brendan McCollam +Erik Rose @@ -10,6 +10,9 @@ Patch by Timothée Peignier. - Fixed Unicode issue on Python 3.1 with coverage (#442) - fixed class level fixture handling in multiprocessing plugin +- Clue in the ``unittest`` module so it no longer prints traceback frames for + our clones of their simple assertion helpers. (#453). + Patch by Erik Rose. 1.1.2 diff --git a/nose/tools/__init__.py b/nose/tools/__init__.py new file mode 100644 index 0000000..ba32301 --- /dev/null +++ b/nose/tools/__init__.py @@ -0,0 +1,11 @@ +""" +Tools for testing +----------------- + +nose.tools provides a few convenience functions to make writing tests +easier. You don't have to use them; nothing in the rest of nose depends +on any of these methods. + +""" +from nose.tools.nontrivial import * +from nose.tools.trivial import * diff --git a/nose/tools.py b/nose/tools/nontrivial.py index 2fb3e75..e47ac62 100644 --- a/nose/tools.py +++ b/nose/tools/nontrivial.py @@ -1,36 +1,16 @@ -""" -Tools for testing ------------------ - -nose.tools provides a few convenience functions to make writing tests -easier. You don't have to use them; nothing in the rest of nose depends -on any of these methods. -""" -import re +"""Tools not exempt from being descended into in tracebacks""" + import time -import unittest -__all__ = ['ok_', 'eq_', 'make_decorator', 'raises', 'set_trace', 'timed', - 'with_setup', 'TimeExpired', 'istest', 'nottest'] +__all__ = ['make_decorator', 'raises', 'set_trace', 'timed', 'with_setup', + 'TimeExpired', 'istest', 'nottest'] class TimeExpired(AssertionError): pass -def ok_(expr, msg=None): - """Shorthand for assert. Saves 3 whole characters! - """ - assert expr, msg - - -def eq_(a, b, msg=None): - """Shorthand for 'assert a == b, "%r != %r" % (a, b) - """ - assert a == b, msg or "%r != %r" % (a, b) - - def make_decorator(func): """ Wraps a test decorator so as to properly replicate metadata @@ -168,27 +148,3 @@ def nottest(func): """ func.__test__ = False return func - -# -# Expose assert* from unittest.TestCase -# - give them pep8 style names -# -caps = re.compile('([A-Z])') - -def pep8(name): - return caps.sub(lambda m: '_' + m.groups()[0].lower(), name) - -class Dummy(unittest.TestCase): - def nop(): - pass -_t = Dummy('nop') - -for at in [ at for at in dir(_t) - if at.startswith('assert') and not '_' in at ]: - pepd = pep8(at) - vars()[pepd] = getattr(_t, at) - __all__.append(pepd) - -del Dummy -del _t -del pep8 diff --git a/nose/tools/trivial.py b/nose/tools/trivial.py new file mode 100644 index 0000000..34d5569 --- /dev/null +++ b/nose/tools/trivial.py @@ -0,0 +1,52 @@ +"""Tools so trivial that tracebacks should not descend into them + +We define the ``__unittest`` symbol in their module namespace so unittest will +skip them when printing tracebacks, just as it does for their corresponding +methods in ``unittest`` proper. + +""" +import re +import unittest + + +__all__ = ['ok_', 'eq_'] + +# Use the same flag as unittest itself to prevent descent into these functions: +__unittest = 1 + + +def ok_(expr, msg=None): + """Shorthand for assert. Saves 3 whole characters! + """ + assert expr, msg + + +def eq_(a, b, msg=None): + """Shorthand for 'assert a == b, "%r != %r" % (a, b) + """ + assert a == b, msg or "%r != %r" % (a, b) + + +# +# Expose assert* from unittest.TestCase +# - give them pep8 style names +# +caps = re.compile('([A-Z])') + +def pep8(name): + return caps.sub(lambda m: '_' + m.groups()[0].lower(), name) + +class Dummy(unittest.TestCase): + def nop(): + pass +_t = Dummy('nop') + +for at in [ at for at in dir(_t) + if at.startswith('assert') and not '_' in at ]: + pepd = pep8(at) + vars()[pepd] = getattr(_t, at) + __all__.append(pepd) + +del Dummy +del _t +del pep8 diff --git a/unit_tests/test_tools.py b/unit_tests/test_tools.py index 839d12b..4dadc02 100644 --- a/unit_tests/test_tools.py +++ b/unit_tests/test_tools.py @@ -31,22 +31,38 @@ class TestTools(unittest.TestCase): else: self.fail("eq_(1, 0) did not raise assertion error") + def test_eq_unittest_flag(self): + """Make sure eq_() is in a namespace that has __unittest = 1. + + This lets tracebacks refrain from descending into the eq_ frame. + + """ + assert '__unittest' in eq_.func_globals + + def test_istest_unittest_flag(self): + """Make sure istest() is not in a namespace that has __unittest = 1. + + That is, make sure our __unittest labeling didn't get overzealous. + + """ + assert '__unittest' not in istest.func_globals + def test_raises(self): from nose.case import FunctionTestCase - + def raise_typeerror(): raise TypeError("foo") def noraise(): pass - + raise_good = raises(TypeError)(raise_typeerror) raise_other = raises(ValueError)(raise_typeerror) no_raise = raises(TypeError)(noraise) tc = FunctionTestCase(raise_good) self.assertEqual(str(tc), "%s.%s" % (__name__, 'raise_typeerror')) - + raise_good() try: raise_other() @@ -67,7 +83,7 @@ class TestTools(unittest.TestCase): def too_slow(): time.sleep(.3) too_slow = timed(.2)(too_slow) - + def quick(): time.sleep(.1) quick = timed(.2)(quick) @@ -88,21 +104,21 @@ class TestTools(unittest.TestCase): def f1(): pass - + f2 = make_decorator(func)(f1) - + assert f2.setup == 'setup' assert f2.teardown == 'teardown' def test_nested_decorators(self): from nose.tools import raises, timed, with_setup - + def test(): pass - + def foo(): pass - + test = with_setup(foo, foo)(test) test = timed(1.0)(test) test = raises(TypeError)(test) @@ -112,7 +128,7 @@ class TestTools(unittest.TestCase): def test_decorator_func_sorting(self): from nose.tools import raises, timed, with_setup from nose.util import func_lineno - + def test1(): pass @@ -136,13 +152,13 @@ class TestTools(unittest.TestCase): self.assertEqual(func_lineno(test1), test1_pos) self.assertEqual(func_lineno(test2), test2_pos) self.assertEqual(func_lineno(test3), test3_pos) - + def test_testcase_funcs(self): import nose.tools tc_asserts = [ at for at in dir(nose.tools) if at.startswith('assert_') ] print tc_asserts - + # FIXME: not sure which of these are in all supported # versions of python assert 'assert_raises' in tc_asserts @@ -153,7 +169,7 @@ class TestTools(unittest.TestCase): from nose.tools import with_setup from nose.case import FunctionTestCase from unittest import TestResult - + called = [] def test(): called.append('test') @@ -163,7 +179,7 @@ class TestTools(unittest.TestCase): def test3(): called.append('test3') - + def s1(): called.append('s1') @@ -172,7 +188,7 @@ class TestTools(unittest.TestCase): def s3(): called.append('s3') - + def t1(): called.append('t1') @@ -181,7 +197,7 @@ class TestTools(unittest.TestCase): def t3(): called.append('t3') - + ws1 = with_setup(s1, t1)(test) case1 = FunctionTestCase(ws1) case1(TestResult()) @@ -202,6 +218,6 @@ class TestTools(unittest.TestCase): case3(TestResult()) self.assertEqual(called, ['s1', 's2', 's3', 'test3', 't3', 't2', 't1']) - + if __name__ == '__main__': unittest.main() |