In test code, it is sometimes useful to monkeypatch a Django method to have stubbed out behavior, so that you can simplify data setup. Even with decent data setup you might want to avoid execution of Django code that is not the target of your test.
The code snippet shown here illustrates a technique to limit the scope of your monkeypatches. It uses the Python "with" statement, which was introduced in 2.5.
The key aspect of the "with" machinery is that you can set up an exit method that gets called even if the code inside the "with" raises an exception. This guarantees that your monkeypatch gets un-monkeyed before any other code gets called.
I don't recommend monkeypatches in production, but if you HAVE to resort to a monkeypatch, I definitely advise using "with" to limit their scope.
The examples on the left illustrate how to suppress versions of reverse() and timesince()--look at the import statements to see which ones I am talking about. Obviously, monkeypatching is not for the faint of the heart, as you need to be able to find the code to monkeypatch in Django source, and you need to be sure there aren't decorators at play.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | from django.core import urlresolvers
from django.utils import timesince
# set up a class to turn off reverse via monkeypatch...we do not care about its details
class PatchReverse:
def __enter__(self):
self.old_method = urlresolvers.reverse
urlresolvers.reverse = lambda view_name, args, kwargs, current_app: 'stub'
def __exit__(self, type, value, traceback):
urlresolvers.reverse = self.old_method
# nor do we care about the details of timesince...note that we monkeypatch the one
# from django.utils...it is harder to monkeypatch template filters due to django
# registration mechanisms
class PatchTimeSince:
def __enter__(self):
self.old_method = timesince.timesince
timesince.timesince = lambda arg: 'stub'
def __exit__(self, type, value, traceback):
timesince.timesince = self.old_method
with PatchReverse():
with PatchTimeSince():
from django.template.loader import render_to_string
render_to_string('activity.html', dict(...))
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 4 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Please login first before commenting.