Patch built-ins
The unittest.mock.patch
decorator can replace any attribute of any module with MagicMock
.
That can be used for unit-testing as a replacement for other code isolation techniques such as dependency injection.
@patch('sms.send')
def test_now(patched_send):
create_client('31205551111')
patched_send.assert_called_with(
'31205551111',
'client created'
)
test_now()
The significant limitation is that patch
doesn't work with built-ins:
# foo.py
from datetime import datetime
def is_odd_hour_now():
print('@@@', datetime)
print('@@@', datetime.now)
return datetime.now().hour % 2 == 1
# test_foo.py
from datetime import datetime
from unittest.mock import patch
from foo import is_odd_hour_now
@patch('datetime.datetime.now')
def test_is_odd_hour_now(patched_now):
patched_now.return_value = \
datetime(2010, 1, 1, 13, 0, 0)
assert is_odd_hour_now()
That will cause TypeError: can't set attributes of built-in/extension type 'datetime.datetime'
.
As a workaround you can patch not the original datetime
, but the reference that foo
holds:
from datetime import datetime
from unittest.mock import patch
from foo import is_odd_hour_now
@patch('foo.datetime')
def test_is_odd_hour_now(patched_datetime):
patched_datetime.now.return_value = \
datetime(2010, 1, 1, 13, 0, 0)