Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mocking a function within a class method

I want to mock a function which is called within a class method while testing the class method in a Django project. Consider the following structure:

app/utils.py

def func():
    ...
    return resp  # outcome is a HTTPResponse object

app/models.py

from app.utils import func

class MyModel(models.Model):
    
    # fields
    
    def call_func(self):
        ...
        func()
        ...

app/tests/test_my_model.py

from django.test import TestCase
import mock    

from app.models import MyModel

class MyModelTestCase(TestCase):

    fixtures = ['my_model_fixtures.json']

    def setUp(self):
        my_model = MyModel.objects.get(id=1)

    @mock.patch('app.utils.func')
    def fake_func(self):
        return mock.MagicMock(headers={'content-type': 'text/html'},
                              status_code=2000, 
                              content="Fake 200 Response"))

    def test_my_model(self):
        my_model.call_func()
        ...  # and asserting the parameters returned by func

When I run the test the mock function fake_func() is avoided and the real func() is called instead. I guess the scope in the mock.patch decorator might be wrong, but I couldn't find a way to make it work. What should I do?

like image 425
VahidM Avatar asked Apr 05 '15 14:04

VahidM


1 Answers

There are three problems with your code:

1) As Daniel Roseman mentioned, you need to patch the module where the function is called, not where it is defined.

2) In addition, you need to decorate the test method that will actually be executing the code that calls the mocked function.

3) Finally, you also need to pass the mocked version in as a parameter to your test method, probably something like this:

fake_response = mock.MagicMock(headers={'content-type': 'text/html'},
                          status_code=2000, 
                          content="Fake 200 Response"))


class MyModelTestCase(TestCase):

    fixtures = ['my_model_fixtures.json']

    def setUp(self):
        my_model = MyModel.objects.get(id=1)

    @mock.patch('app.models.func', return_value=fake_response)
    def test_my_model(self, fake_response):  # the mock goes in as a param or else you get number of arguments error!
        my_model.call_func()
        self.assertTrue(fake_response.called)
like image 138
erewok Avatar answered Oct 19 '22 23:10

erewok