Closes issue 17660. You no longer need to explicitly pass create=True when patching builtin names.
This commit is contained in:
parent
fba913f77a
commit
fddcfa27fa
@ -1031,6 +1031,12 @@ patch
|
|||||||
default because it can be dangerous. With it switched on you can write
|
default because it can be dangerous. With it switched on you can write
|
||||||
passing tests against APIs that don't actually exist!
|
passing tests against APIs that don't actually exist!
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
.. versionchanged:: 3.5
|
||||||
|
If you are patching builtins in a module then you don't
|
||||||
|
need to pass `create=True`, it will be added by default.
|
||||||
|
|
||||||
Patch can be used as a `TestCase` class decorator. It works by
|
Patch can be used as a `TestCase` class decorator. It works by
|
||||||
decorating each test method in the class. This reduces the boilerplate
|
decorating each test method in the class. This reduces the boilerplate
|
||||||
code when your test methods share a common patchings set. `patch` finds
|
code when your test methods share a common patchings set. `patch` finds
|
||||||
@ -1401,6 +1407,21 @@ It is also possible to stop all patches which have been started by using
|
|||||||
|
|
||||||
Stop all active patches. Only stops patches started with `start`.
|
Stop all active patches. Only stops patches started with `start`.
|
||||||
|
|
||||||
|
.. patch-builtins:
|
||||||
|
|
||||||
|
patch builtins
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
You can patch any builtins within a module. The following example patches
|
||||||
|
builtin `ord`:
|
||||||
|
|
||||||
|
>>> @patch('__main__.ord')
|
||||||
|
... def test(mock_ord):
|
||||||
|
... mock_ord.return_value = 101
|
||||||
|
... print(ord('c'))
|
||||||
|
...
|
||||||
|
>>> test()
|
||||||
|
101
|
||||||
|
|
||||||
|
|
||||||
TEST_PREFIX
|
TEST_PREFIX
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
@ -2011,7 +2032,7 @@ Mocking context managers with a :class:`MagicMock` is common enough and fiddly
|
|||||||
enough that a helper function is useful.
|
enough that a helper function is useful.
|
||||||
|
|
||||||
>>> m = mock_open()
|
>>> m = mock_open()
|
||||||
>>> with patch('__main__.open', m, create=True):
|
>>> with patch('__main__.open', m):
|
||||||
... with open('foo', 'w') as h:
|
... with open('foo', 'w') as h:
|
||||||
... h.write('some stuff')
|
... h.write('some stuff')
|
||||||
...
|
...
|
||||||
@ -2026,7 +2047,7 @@ enough that a helper function is useful.
|
|||||||
|
|
||||||
And for reading files:
|
And for reading files:
|
||||||
|
|
||||||
>>> with patch('__main__.open', mock_open(read_data='bibble'), create=True) as m:
|
>>> with patch('__main__.open', mock_open(read_data='bibble')) as m:
|
||||||
... with open('foo') as h:
|
... with open('foo') as h:
|
||||||
... result = h.read()
|
... result = h.read()
|
||||||
...
|
...
|
||||||
|
@ -27,9 +27,13 @@ __version__ = '1.0'
|
|||||||
import inspect
|
import inspect
|
||||||
import pprint
|
import pprint
|
||||||
import sys
|
import sys
|
||||||
|
import builtins
|
||||||
|
from types import ModuleType
|
||||||
from functools import wraps, partial
|
from functools import wraps, partial
|
||||||
|
|
||||||
|
|
||||||
|
_builtins = {name for name in dir(builtins) if not name.startswith('_')}
|
||||||
|
|
||||||
BaseExceptions = (BaseException,)
|
BaseExceptions = (BaseException,)
|
||||||
if 'java' in sys.platform:
|
if 'java' in sys.platform:
|
||||||
# jython
|
# jython
|
||||||
@ -1166,6 +1170,9 @@ class _patch(object):
|
|||||||
else:
|
else:
|
||||||
local = True
|
local = True
|
||||||
|
|
||||||
|
if name in _builtins and isinstance(target, ModuleType):
|
||||||
|
self.create = True
|
||||||
|
|
||||||
if not self.create and original is DEFAULT:
|
if not self.create and original is DEFAULT:
|
||||||
raise AttributeError(
|
raise AttributeError(
|
||||||
"%s does not have the attribute %r" % (target, name)
|
"%s does not have the attribute %r" % (target, name)
|
||||||
|
@ -377,7 +377,7 @@ class PatchTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_patchobject_wont_create_by_default(self):
|
def test_patchobject_wont_create_by_default(self):
|
||||||
try:
|
try:
|
||||||
@patch.object(SomeClass, 'frooble', sentinel.Frooble)
|
@patch.object(SomeClass, 'ord', sentinel.Frooble)
|
||||||
def test():
|
def test():
|
||||||
self.fail('Patching non existent attributes should fail')
|
self.fail('Patching non existent attributes should fail')
|
||||||
|
|
||||||
@ -386,7 +386,27 @@ class PatchTest(unittest.TestCase):
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
self.fail('Patching non existent attributes should fail')
|
self.fail('Patching non existent attributes should fail')
|
||||||
self.assertFalse(hasattr(SomeClass, 'frooble'))
|
self.assertFalse(hasattr(SomeClass, 'ord'))
|
||||||
|
|
||||||
|
|
||||||
|
def test_patch_builtins_without_create(self):
|
||||||
|
@patch(__name__+'.ord')
|
||||||
|
def test_ord(mock_ord):
|
||||||
|
mock_ord.return_value = 101
|
||||||
|
return ord('c')
|
||||||
|
|
||||||
|
@patch(__name__+'.open')
|
||||||
|
def test_open(mock_open):
|
||||||
|
m = mock_open.return_value
|
||||||
|
m.read.return_value = 'abcd'
|
||||||
|
|
||||||
|
fobj = open('doesnotexists.txt')
|
||||||
|
data = fobj.read()
|
||||||
|
fobj.close()
|
||||||
|
return data
|
||||||
|
|
||||||
|
self.assertEqual(test_ord(), 101)
|
||||||
|
self.assertEqual(test_open(), 'abcd')
|
||||||
|
|
||||||
|
|
||||||
def test_patch_with_static_methods(self):
|
def test_patch_with_static_methods(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user