13
votes

I'm trying to use patch to return the a Mock from within a method. The basic structure is as follows:

MyCode.py

class MyClass:

    def __init__(self, first_name, last_name):
        self.first = first_name
        self.last = last_name

    def get_greeting(self):
        return 'Hello {f} {l}'.format(f=self.first, l=self.last)


def get_new_greeting(first_name, last_name):
    obj = MyClass(first_name, last_name)
    return obj.get_greeting()


my_code_test.py

import unittest
from mock import Mock, patch
import my_code

class TestMyCode(unittest.TestCase):
    def setUp(self):
        pass

    @patch('my_code.MyClass')
    def test_get_greeting(self, MockClass):
        instance = MockClass.return_value
        mock_greeting = 'Hello Me'
        instance.get_greeting.return_value = mock_greeting

        greeting = my_code.get_new_greeting('john', 'doe')
        self.assertEqual(greeting, mock_greeting)


if __name__ == '__main__':
    unittest.main()

The code above works fine for me. However, when I apply the same pattern to the real code that I'm trying to test, the real object (not the mock one) gets returned in the method being tested. I can't see any differences. The only think that is a bit different is that the real class is defined in a init.py file. I'm not sure if this make a difference or not? Has any seen this before?

Note: the actual lib is twilio 3.3.5 and I'm using Python 2.6.5 and Django 1.3.1 and Mock 0.7.2

1
You probably need to post the code that isn't working, rather than the code that is.Daniel Roseman
@DanielRoseman very valid point. The reason that I used this approach was that I figured very few people would have the twilio package and might not want to install it (although this isn't a big deal if you are using virtualenv), and I wanted to show that I understood the basic principle of what I needed to do. Thanks for your reply.David S

1 Answers

11
votes

I figured it out. It had nothing to do with __init__.py file. It was (as usual) my fault! :)

Just for anyone that is every trying to use Mock and patch with Twilio and SMS in the future, here is the solution:

I was Mocking the class twilio.rest.TwilioRestClient But, things are chained together and I needed to call patch on the inner class called SmsMessage. So, for my unit test, this works well:

@patch('twilio.rest.resources.SmsMessages')
def test_send_msg_valid_args(self, MockClass):
    instance = MockClass.return_value
    instance.create.return_value = None
    to_number = '+15555555555'
    msg = 'Hello world'
    send_sms(to_number, msg)

    instance.create.assert_called_once_with(to=to_number, body=msg, from_=default_from_number)

note: send_sms is really the function that I'm trying to test. I just wanted to make sure that it was calling twilio as expected and supplying the default_from_number. The value default_from_number is defined in the settings file and not really important for this example.