If you aren't familiar with the term, monkey patching means changing code at runtime. Only possible in wicked languages like python, it can be a major source of headaches if you do this unexpectedly (or if somebody else does it unexpectedly)
I'm currently using Twilio for handling my phone number redirection service for mobile phones, Churp. In my unit tests I needed to make sure that my requests and responses were being handled properly, but I didn't want to do any real requests to Twilio every time I run the suite. So I monkey patched the Twilio rest client for my tests. It looks something like this:
class FakeTwilioRestClient(object):
#this is a class variable that I use for switching the return value of the Fake Rest Client
find_number = False
def __init__(self, account_sid, account_token):
# basically copy the __init__ of the real class here since this class
# will be initialized just like the real one
pass
def request(self, request_resource, method_type, params=None):
# parameters must be the same as the real method since that's how it's
# going to be called inside your code
if not self.find_number:
return '{"friendly_name": "(604) 777 8856"}'
else:
return """{"available_phone_numbers": [{"friendly_name": "(604) 777 8856"}]}"""
Now when the view uses the client, it's been replaced by what's above, instead of doing a real request to Twilio. So that is the client, here is what the test looks like.
def test_my_twilio_view(self):
from myviews import twilio
original_account_class = twilio.Account
twilio.Account = FakeTwilioClient
.....
#fix the monkey patching for the other tests
twilio.Account = original_account_class
def test_my_twilio_view_2(self):
from myviews import twilio
original_account_class = twilio.Account
FakeTwilioClient.find_number = True #now the fake client will return a different valuetwilio.Account = FakeTwilioClient
One thing that took me a while to really get was how to monkey patch the imports right. What won't work is this:
def test(self):
import twilio
twilio.Account = FakeTwilioClient
This won't patch anything. It is important to import the module you're patching from the module you're testing, or nothing will happen and you might be scratching your head as to why (python modules have their own scope, this is why it's important to import the patched module from the right place and not from your python path)
As always, all comments and / or corrections are welcome. Part of the reason for this blog is to help me learn while trying to give back to the community that has helped me so much.
1 comment:
Hey, I need some help ! I am having a sign up with gmail option in my website .I do not want to test the gmail api .How do i write a monkey patching or mock the gmail response..
Post a Comment