Reputation: 375
I am having trouble getting my test to run as expected. I am trying to mock the return value for two properties and a method for one test but instead of getting the desired return value I get a MagicMock object.
I can not figure out how to do this. The thing that irritates me the most is that mocking the method works as expected but for the two properties it does not. Is this a problem I am having because I am using properties or because of the foreignkey relationships or am I doing something basic wrong?
I am using Django 1.8, Python2.7, model-mommy, unittests, mock
Here are some snippets of my code, I hope they are sufficient to understand the situation:
App1 called producers
# In producers.models.Producer:
@property
def is_valid(self):
# do stuff
return True
App2 called customers
# In customers.models.Customer:
@property
def is_valid(self):
# do stuff
return True
def is_allowed_to_purchase_from_producer(producer):
# do stuff
return True
App3 called purchases
# In purchases.models
class Purchase(BaseModel):
producer = ForeignKey('Producers.Producer', related_name="purchase")
customer = ForeignKey('Customers.Customer', related_name="purchase")
def clean(self):
if not self.producer.is_valid:
rasie ValidationError
if not self.customer.is_valid:
raise ValidationError
if not self.customer.is_allowed_to_purchase_from_producer(self.producer):
raise ValidationError
A test for the clean method of the Purchase model
# test_models.py, in PurchaseTestSuite
@mock.patch('producers.models.Producer.is_valid')
@mock.patch('customers.models.Customer.is_valid')
@mock.patch('customers.models.Customer.is_allowed_to_purchase_from_producer')
def test__clean(self, mock__customer_is_allowed_to_purchase, mock__customer_is_valid, mock__producer_is_valid):
mock__producer_is_valid.return_value = True
mock__customer_is_valid.return_value = False
mock__customer_is_allowed_to_purchase.return_value = False
valid_purchase.clean()
<MagicMock
name='is_valid' id='4465040784'>
<MagicMock name='is_valid' id='4465109520'>
When asserting if the properties have been called I get False but for the method I get True. Where is the differnce? What am I not seeing?
Upvotes: 4
Views: 1728
Reputation: 375
Thanks to Daniel Roseman's comment and link to PropertyMock I managed to figure out how to get the tests running.
A mock intended to be used as a property, or other descriptor, on a class. PropertyMock provides get() and set() methods so you can specify a return value when it is fetched.
So for the example above, the simple solution is to use PropertyMock as follows for all properties:
@mock.patch('producers.models.Producer.is_valid', new_callable=mock.PropertyMock)
The rest stays the same as in the above example.
I hope this helps if someone is having a similar problem.
Upvotes: 1