jimfawkes
jimfawkes

Reputation: 375

Why are my mocked properties not returning the specified value but a MagicMock object and my mocked method is returning the expected value?

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()

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

Answers (1)

jimfawkes
jimfawkes

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

Related Questions