pytest_mock.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. from __future__ import unicode_literals
  2. import inspect
  3. import sys
  4. import pytest
  5. from _pytest_mock_version import version
  6. __version__ = version
  7. # pseudo-six; if this starts to require more than this, depend on six already
  8. if sys.version_info[0] == 2: # pragma: no cover
  9. text_type = unicode # noqa
  10. else:
  11. text_type = str
  12. def _get_mock_module(config):
  13. """
  14. Import and return the actual "mock" module. By default this is "mock" for Python 2 and
  15. "unittest.mock" for Python 3, but the user can force to always use "mock" on Python 3 using
  16. the mock_use_standalone_module ini option.
  17. """
  18. if not hasattr(_get_mock_module, '_module'):
  19. use_standalone_module = parse_ini_boolean(config.getini('mock_use_standalone_module'))
  20. if sys.version_info[0] == 2 or use_standalone_module:
  21. import mock
  22. _get_mock_module._module = mock
  23. else:
  24. import unittest.mock
  25. _get_mock_module._module = unittest.mock
  26. return _get_mock_module._module
  27. class MockFixture(object):
  28. """
  29. Fixture that provides the same interface to functions in the mock module,
  30. ensuring that they are uninstalled at the end of each test.
  31. """
  32. def __init__(self, config):
  33. self._patches = [] # list of mock._patch objects
  34. self._mocks = [] # list of MagicMock objects
  35. self.mock_module = mock_module = _get_mock_module(config)
  36. self.patch = self._Patcher(self._patches, self._mocks, mock_module)
  37. # aliases for convenience
  38. self.Mock = mock_module.Mock
  39. self.MagicMock = mock_module.MagicMock
  40. self.NonCallableMock = mock_module.NonCallableMock
  41. self.PropertyMock = mock_module.PropertyMock
  42. self.call = mock_module.call
  43. self.ANY = mock_module.ANY
  44. self.DEFAULT = mock_module.DEFAULT
  45. self.create_autospec = mock_module.create_autospec
  46. self.sentinel = mock_module.sentinel
  47. self.mock_open = mock_module.mock_open
  48. def resetall(self):
  49. """
  50. Call reset_mock() on all patchers started by this fixture.
  51. """
  52. for m in self._mocks:
  53. m.reset_mock()
  54. def stopall(self):
  55. """
  56. Stop all patchers started by this fixture. Can be safely called multiple
  57. times.
  58. """
  59. for p in reversed(self._patches):
  60. p.stop()
  61. self._patches[:] = []
  62. self._mocks[:] = []
  63. def spy(self, obj, name):
  64. """
  65. Creates a spy of method. It will run method normally, but it is now
  66. possible to use `mock` call features with it, like call count.
  67. :param object obj: An object.
  68. :param unicode name: A method in object.
  69. :rtype: mock.MagicMock
  70. :return: Spy object.
  71. """
  72. method = getattr(obj, name)
  73. autospec = inspect.ismethod(method) or inspect.isfunction(method)
  74. # Can't use autospec classmethod or staticmethod objects
  75. # see: https://bugs.python.org/issue23078
  76. if inspect.isclass(obj):
  77. # Bypass class descriptor:
  78. # http://stackoverflow.com/questions/14187973/python3-check-if-method-is-static
  79. try:
  80. value = obj.__getattribute__(obj, name)
  81. except AttributeError:
  82. pass
  83. else:
  84. if isinstance(value, (classmethod, staticmethod)):
  85. autospec = False
  86. result = self.patch.object(obj, name, side_effect=method,
  87. autospec=autospec)
  88. return result
  89. def stub(self, name=None):
  90. """
  91. Creates a stub method. It accepts any arguments. Ideal to register to
  92. callbacks in tests.
  93. :param name: the constructed stub's name as used in repr
  94. :rtype: mock.MagicMock
  95. :return: Stub object.
  96. """
  97. return self.mock_module.MagicMock(spec=lambda *args, **kwargs: None, name=name)
  98. class _Patcher(object):
  99. """
  100. Object to provide the same interface as mock.patch, mock.patch.object,
  101. etc. We need this indirection to keep the same API of the mock package.
  102. """
  103. def __init__(self, patches, mocks, mock_module):
  104. self._patches = patches
  105. self._mocks = mocks
  106. self.mock_module = mock_module
  107. def _start_patch(self, mock_func, *args, **kwargs):
  108. """Patches something by calling the given function from the mock
  109. module, registering the patch to stop it later and returns the
  110. mock object resulting from the mock call.
  111. """
  112. p = mock_func(*args, **kwargs)
  113. mocked = p.start()
  114. self._patches.append(p)
  115. if hasattr(mocked, 'reset_mock'):
  116. self._mocks.append(mocked)
  117. return mocked
  118. def object(self, *args, **kwargs):
  119. """API to mock.patch.object"""
  120. return self._start_patch(self.mock_module.patch.object, *args, **kwargs)
  121. def multiple(self, *args, **kwargs):
  122. """API to mock.patch.multiple"""
  123. return self._start_patch(self.mock_module.patch.multiple, *args,
  124. **kwargs)
  125. def dict(self, *args, **kwargs):
  126. """API to mock.patch.dict"""
  127. return self._start_patch(self.mock_module.patch.dict, *args, **kwargs)
  128. def __call__(self, *args, **kwargs):
  129. """API to mock.patch"""
  130. return self._start_patch(self.mock_module.patch, *args, **kwargs)
  131. @pytest.yield_fixture
  132. def mocker(pytestconfig):
  133. """
  134. return an object that has the same interface to the `mock` module, but
  135. takes care of automatically undoing all patches after each test method.
  136. """
  137. result = MockFixture(pytestconfig)
  138. yield result
  139. result.stopall()
  140. @pytest.fixture
  141. def mock(mocker):
  142. """
  143. Same as "mocker", but kept only for backward compatibility.
  144. """
  145. import warnings
  146. warnings.warn('"mock" fixture has been deprecated, use "mocker" instead',
  147. DeprecationWarning)
  148. return mocker
  149. _mock_module_patches = []
  150. _mock_module_originals = {}
  151. def assert_wrapper(__wrapped_mock_method__, *args, **kwargs):
  152. __tracebackhide__ = True
  153. try:
  154. __wrapped_mock_method__(*args, **kwargs)
  155. return
  156. except AssertionError as e:
  157. if getattr(e, '_mock_introspection_applied', 0):
  158. msg = text_type(e)
  159. else:
  160. __mock_self = args[0]
  161. msg = text_type(e)
  162. if __mock_self.call_args is not None:
  163. actual_args, actual_kwargs = __mock_self.call_args
  164. msg += '\n\npytest introspection follows:\n'
  165. try:
  166. assert actual_args == args[1:]
  167. except AssertionError as e:
  168. msg += '\nArgs:\n' + text_type(e)
  169. try:
  170. assert actual_kwargs == kwargs
  171. except AssertionError as e:
  172. msg += '\nKwargs:\n' + text_type(e)
  173. e = AssertionError(msg)
  174. e._mock_introspection_applied = True
  175. raise e
  176. def wrap_assert_not_called(*args, **kwargs):
  177. __tracebackhide__ = True
  178. assert_wrapper(_mock_module_originals["assert_not_called"],
  179. *args, **kwargs)
  180. def wrap_assert_called_with(*args, **kwargs):
  181. __tracebackhide__ = True
  182. assert_wrapper(_mock_module_originals["assert_called_with"],
  183. *args, **kwargs)
  184. def wrap_assert_called_once(*args, **kwargs):
  185. __tracebackhide__ = True
  186. assert_wrapper(_mock_module_originals["assert_called_once"],
  187. *args, **kwargs)
  188. def wrap_assert_called_once_with(*args, **kwargs):
  189. __tracebackhide__ = True
  190. assert_wrapper(_mock_module_originals["assert_called_once_with"],
  191. *args, **kwargs)
  192. def wrap_assert_has_calls(*args, **kwargs):
  193. __tracebackhide__ = True
  194. assert_wrapper(_mock_module_originals["assert_has_calls"],
  195. *args, **kwargs)
  196. def wrap_assert_any_call(*args, **kwargs):
  197. __tracebackhide__ = True
  198. assert_wrapper(_mock_module_originals["assert_any_call"],
  199. *args, **kwargs)
  200. def wrap_assert_called(*args, **kwargs):
  201. __tracebackhide__ = True
  202. assert_wrapper(_mock_module_originals["assert_called"],
  203. *args, **kwargs)
  204. def wrap_assert_methods(config):
  205. """
  206. Wrap assert methods of mock module so we can hide their traceback and
  207. add introspection information to specified argument asserts.
  208. """
  209. # Make sure we only do this once
  210. if _mock_module_originals:
  211. return
  212. mock_module = _get_mock_module(config)
  213. wrappers = {
  214. 'assert_called': wrap_assert_called,
  215. 'assert_called_once': wrap_assert_called_once,
  216. 'assert_called_with': wrap_assert_called_with,
  217. 'assert_called_once_with': wrap_assert_called_once_with,
  218. 'assert_any_call': wrap_assert_any_call,
  219. 'assert_has_calls': wrap_assert_has_calls,
  220. 'assert_not_called': wrap_assert_not_called,
  221. }
  222. for method, wrapper in wrappers.items():
  223. try:
  224. original = getattr(mock_module.NonCallableMock, method)
  225. except AttributeError: # pragma: no cover
  226. continue
  227. _mock_module_originals[method] = original
  228. patcher = mock_module.patch.object(
  229. mock_module.NonCallableMock, method, wrapper)
  230. patcher.start()
  231. _mock_module_patches.append(patcher)
  232. if hasattr(config, 'add_cleanup'):
  233. add_cleanup = config.add_cleanup
  234. else:
  235. # pytest 2.7 compatibility
  236. add_cleanup = config._cleanup.append
  237. add_cleanup(unwrap_assert_methods)
  238. def unwrap_assert_methods():
  239. for patcher in _mock_module_patches:
  240. patcher.stop()
  241. _mock_module_patches[:] = []
  242. _mock_module_originals.clear()
  243. def pytest_addoption(parser):
  244. parser.addini('mock_traceback_monkeypatch',
  245. 'Monkeypatch the mock library to improve reporting of the '
  246. 'assert_called_... methods',
  247. default=True)
  248. parser.addini('mock_use_standalone_module',
  249. 'Use standalone "mock" (from PyPI) instead of builtin "unittest.mock" '
  250. 'on Python 3',
  251. default=False)
  252. def parse_ini_boolean(value):
  253. if value in (True, False):
  254. return value
  255. try:
  256. return {'true': True, 'false': False}[value.lower()]
  257. except KeyError:
  258. raise ValueError('unknown string for bool: %r' % value)
  259. def pytest_configure(config):
  260. tb = config.getoption('--tb')
  261. if parse_ini_boolean(config.getini('mock_traceback_monkeypatch')) and tb != 'native':
  262. wrap_assert_methods(config)