This is my first file called user.py
from account import Account
class User:
def __init__(self, id):
self.id = id
self._account = None
@property
def account(self):
if not self._account:
self._account = Account(self.id)
return self._account
@property
def has_discount(self)
return self.account.discount_id > 0
I have a second file called account.py
class Account:
def __init__(self, user_id):
# some process to load DB data
self.account = load_account(user_id)
# do something after this to initialize account properties like discount, etc
@property
def discount_id(self):
return self.discount_id
My goal is to test user.py. One of the things I want to do is to mock the Account object in user.py for the 'has_discount' property decorator. I want to test different scenarios where has_discount will return either 0 or any other number.
How do I do this using patch where I can mock the Account object in the User class to return custom values so I can try different tests?
If you want to mock an object for the duration of your entire test function, you can use patch() as a function decorator. These functions are now in their own file, separate from their tests. Next, you'll re-create your tests in a file called tests.py .
So what is the difference between them? MagicMock is a subclass of Mock . It contains all magic methods pre-created and ready to use (e.g. __str__ , __len__ , etc.). Therefore, you should use MagicMock when you need magic methods, and Mock if you don't need them.
Rather than hacking on top of Python's import machinery, you can simply add the mocked module into sys. path , and have Python prefer it over the original module. Now, when the test suite is run, the mocked-lib subdirectory is prepended into sys. path and import A uses B from mocked-lib .
Because the user
module imports Account
in to its own namespace patching has to be done there instead of the account
module. In other words you have to temporarily change what the name Account
in the user
module refers to:
from user import User
from unittest.mock import patch
with patch('user.Account') as MockAccount:
MockAccount.return_value.discount_id = 1
u = User(1)
print(u.has_discount)
# True
with patch('user.Account') as MockAccount:
MockAccount.return_value.discount_id = 0
u = User(1)
print(u.has_discount)
# False
I want to test different scenarios where has_discount will return either 0 or any other number.
In its current implementation User.has_discount
will always return either True
or False
. Did you mean Account.discount_id
?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With