/nose/tools.py

https://bitbucket.org/jpellerin/nose/ · Python · 194 lines · 135 code · 17 blank · 42 comment · 15 complexity · 8187b9d8b8fc9b69c2ca0459e50602fd MD5 · raw file

  1. """
  2. Tools for testing
  3. -----------------
  4. nose.tools provides a few convenience functions to make writing tests
  5. easier. You don't have to use them; nothing in the rest of nose depends
  6. on any of these methods.
  7. """
  8. import re
  9. import time
  10. import unittest
  11. __all__ = ['ok_', 'eq_', 'make_decorator', 'raises', 'set_trace', 'timed',
  12. 'with_setup', 'TimeExpired', 'istest', 'nottest']
  13. class TimeExpired(AssertionError):
  14. pass
  15. def ok_(expr, msg=None):
  16. """Shorthand for assert. Saves 3 whole characters!
  17. """
  18. assert expr, msg
  19. def eq_(a, b, msg=None):
  20. """Shorthand for 'assert a == b, "%r != %r" % (a, b)
  21. """
  22. assert a == b, msg or "%r != %r" % (a, b)
  23. def make_decorator(func):
  24. """
  25. Wraps a test decorator so as to properly replicate metadata
  26. of the decorated function, including nose's additional stuff
  27. (namely, setup and teardown).
  28. """
  29. def decorate(newfunc):
  30. if hasattr(func, 'compat_func_name'):
  31. name = func.compat_func_name
  32. else:
  33. name = func.__name__
  34. newfunc.__dict__ = func.__dict__
  35. newfunc.__doc__ = func.__doc__
  36. newfunc.__module__ = func.__module__
  37. if not hasattr(newfunc, 'compat_co_firstlineno'):
  38. newfunc.compat_co_firstlineno = func.func_code.co_firstlineno
  39. try:
  40. newfunc.__name__ = name
  41. except TypeError:
  42. # can't set func name in 2.3
  43. newfunc.compat_func_name = name
  44. return newfunc
  45. return decorate
  46. def raises(*exceptions):
  47. """Test must raise one of expected exceptions to pass.
  48. Example use::
  49. @raises(TypeError, ValueError)
  50. def test_raises_type_error():
  51. raise TypeError("This test passes")
  52. @raises(Exception)
  53. def test_that_fails_by_passing():
  54. pass
  55. If you want to test many assertions about exceptions in a single test,
  56. you may want to use `assert_raises` instead.
  57. """
  58. valid = ' or '.join([e.__name__ for e in exceptions])
  59. def decorate(func):
  60. name = func.__name__
  61. def newfunc(*arg, **kw):
  62. try:
  63. func(*arg, **kw)
  64. except exceptions:
  65. pass
  66. except:
  67. raise
  68. else:
  69. message = "%s() did not raise %s" % (name, valid)
  70. raise AssertionError(message)
  71. newfunc = make_decorator(func)(newfunc)
  72. return newfunc
  73. return decorate
  74. def set_trace():
  75. """Call pdb.set_trace in the calling frame, first restoring
  76. sys.stdout to the real output stream. Note that sys.stdout is NOT
  77. reset to whatever it was before the call once pdb is done!
  78. """
  79. import pdb
  80. import sys
  81. stdout = sys.stdout
  82. sys.stdout = sys.__stdout__
  83. pdb.Pdb().set_trace(sys._getframe().f_back)
  84. def timed(limit):
  85. """Test must finish within specified time limit to pass.
  86. Example use::
  87. @timed(.1)
  88. def test_that_fails():
  89. time.sleep(.2)
  90. """
  91. def decorate(func):
  92. def newfunc(*arg, **kw):
  93. start = time.time()
  94. func(*arg, **kw)
  95. end = time.time()
  96. if end - start > limit:
  97. raise TimeExpired("Time limit (%s) exceeded" % limit)
  98. newfunc = make_decorator(func)(newfunc)
  99. return newfunc
  100. return decorate
  101. def with_setup(setup=None, teardown=None):
  102. """Decorator to add setup and/or teardown methods to a test function::
  103. @with_setup(setup, teardown)
  104. def test_something():
  105. " ... "
  106. Note that `with_setup` is useful *only* for test functions, not for test
  107. methods or inside of TestCase subclasses.
  108. """
  109. def decorate(func, setup=setup, teardown=teardown):
  110. if setup:
  111. if hasattr(func, 'setup'):
  112. _old_s = func.setup
  113. def _s():
  114. setup()
  115. _old_s()
  116. func.setup = _s
  117. else:
  118. func.setup = setup
  119. if teardown:
  120. if hasattr(func, 'teardown'):
  121. _old_t = func.teardown
  122. def _t():
  123. _old_t()
  124. teardown()
  125. func.teardown = _t
  126. else:
  127. func.teardown = teardown
  128. return func
  129. return decorate
  130. def istest(func):
  131. """Decorator to mark a function or method as a test
  132. """
  133. func.__test__ = True
  134. return func
  135. def nottest(func):
  136. """Decorator to mark a function or method as *not* a test
  137. """
  138. func.__test__ = False
  139. return func
  140. #
  141. # Expose assert* from unittest.TestCase
  142. # - give them pep8 style names
  143. #
  144. caps = re.compile('([A-Z])')
  145. def pep8(name):
  146. return caps.sub(lambda m: '_' + m.groups()[0].lower(), name)
  147. class Dummy(unittest.TestCase):
  148. def nop():
  149. pass
  150. _t = Dummy('nop')
  151. for at in [ at for at in dir(_t)
  152. if at.startswith('assert') and not '_' in at ]:
  153. pepd = pep8(at)
  154. vars()[pepd] = getattr(_t, at)
  155. __all__.append(pepd)
  156. del Dummy
  157. del _t
  158. del pep8