Mock
Tip
If you have any issues with patch
not working as expected, check
the notes ref using mock
(without py.test
) below…
The unittest.mock library is included with python 3.
To use the mock module with py.test
, install the pytest-mock module:
pip install pytest-mock
Examples (using py.test
)
I like this syntax:
from unittest.mock import patch, Mock, mock_open
def mock_ip():
return '12.13.14.15'
@patch('customer.Customer.create', return_value='153356')
@patch('service.ip_address_from_url', return_value=mock_ip())
@patch.multiple('customer.Customer',
id_for_email=Mock(return_value=46419),
get_customer=Mock(side_effect=[{}, mock_simple]),
)
def test_register(self, patch_ip, patch_create):
Tip
The patch variables e.g. patch_ip
are in reverse order i.e.
The first @patch
decorator is passed to the function in the
second position.
@pytest.mark.django_db
def test_post_card_refresh(client, mocker):
mocker.patch('stripe.Customer.create')
Exception
from unittest import mock
@pytest.mark.django_db
def test_process_payments_fail(mocker):
with mock.patch('stripe.Customer.create') as mock_customer:
mock_customer.side_effect = CheckoutError('Mock')
Property
To mock a property e.g:
class SalesLedger(models.Model):
@property
def checkout_can_charge(self):
return True
Use the PropertyMock
e.g:
with mock.patch(
'example_checkout.models.SalesLedger.checkout_can_charge',
new_callable=mock.PropertyMock,
) as mock_checkout_can_charge:
# mock return
mock_checkout_can_charge.return_value = False
Issues
import
I tried to mock a function like this:
def search(index_name, criteria, page_number=None):
But it didn’t seem to work, so I made a private function e.g. _search
and
mocked that instead:
def search(index_name, criteria, page_number=None):
# call the private function
return _search(index_name, criteria, page_number)
# the mock
with mock.patch('search.service._search') as m:
Note
I don’t understand why this works, but it does!
with
I was using with mock
and put the code I was testing after the with
block… so there was no mocking by the time my code was running!
mock (without py.test
)
method
Using mock
with py.test
appears to stop mock
working as documented.
If you have any issues, try ignoring the mocker
fixture:
from unittest import mock
with mock.patch('stripe.Customer.retrieve') as mock_retrieve:
mock_retrieve.return_value = {
'default_card': '1234',
'cards': {
'data': [
{
'id': '1234',
'exp_month': '8',
'exp_year': '1986',
},
],
},
}
Thank you Helen Sherwood-Taylor for your excellent talk on Managing mocks
object
I was testing some code in another module. The import and code in the other module looked like this:
from django.core import mail
msg = mail.EmailMultiAlternatives(
# ... do some work...
for resp in msg.mandrill_response:
Here is the test code:
from unittest import mock
with mock.patch('django.core.mail.EmailMultiAlternatives') as mock_mail:
mock_mail.return_value.mandrill_response = [{
"email": "abc@test.com",
"status": "rejected",
"_id": "123",
"reject_reason": "hard-bounce"
}]
Note
I was surprised to see that setting up the return value for the
mandrill_response
was written with the return_value
before
the method name.
Note
You have to patch the correct import path (see Where to patch).
I spent hours trying to find where to patch, but the issue was a
completely different one (I hadn’t got my test code inside the
with
block).