Login

Modify requests in your unit tests (improvement on RequestFactory)

Author:
vaughnkoch
Posted:
October 7, 2010
Language:
Python
Version:
1.2
Score:
2 (after 2 ratings)

This is an update to Simon Willison's snippet http://djangosnippets.org/snippets/963/, along with one of the comments in that snippet.

This class lets you create a Request object that's gone through all the middleware. Suitable for unit testing when you need to modify something on the request directly, or pass in a mock object. (note: see http://labix.org/mocker for details on how to mock requests for testing)

Example on how to use:

from django.test import TestCase from yourapp import your_view from yourutils import RequestFactory

class YourTestClass(TestCase): def setUp(self): pass def tearDown(self): pass

# Create your own request, which you can modify, instead of using self.client.
def test_your_view(self):
    # Create your request object
    rf = RequestFactory()
    request = rf.get('/your-url-here/')

    # ... modify the request to your liking ...

    response = your_view(request)
    self.assertEqual(response.status_code, 200)

Suggestions/improvements are welcome. :)

 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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
from django.test import Client
from django.core.handlers.wsgi import WSGIRequest
from django.core.handlers.base import BaseHandler

# Adapted from Simon Willison's snippet: http://djangosnippets.org/snippets/963/.
class RequestFactory(Client):
    """
    Class that lets you create mock Request objects for use in testing.
    
    Usage:
    
    rf = RequestFactory()
    get_request = rf.get('/hello/')
    post_request = rf.post('/submit/', {'foo': 'bar'})
    
    This class re-uses the django.test.client.Client interface, docs here:
    http://www.djangoproject.com/documentation/testing/#the-test-client
    
    Once you have a request object you can pass it to any view function, 
    just as if that view had been hooked up using a URLconf.
    
    """
    def request(self, **request):
        """
        Similar to parent class, but returns the request object as soon as it
        has created it.
        """
        environ = {
            'HTTP_COOKIE': self.cookies,
            'PATH_INFO': '/',
            'QUERY_STRING': '',
            'REQUEST_METHOD': 'GET',
            'SCRIPT_NAME': '',
            'SERVER_NAME': 'testserver',
            'SERVER_PORT': 80,
            'SERVER_PROTOCOL': 'HTTP/1.1',
        }
        environ.update(self.defaults)
        environ.update(request)
        request = WSGIRequest(environ)
        
        handler = BaseHandler()
        handler.load_middleware()
        for middleware_method in handler._request_middleware:
            if middleware_method(request):
                raise Exception("Couldn't create request object - "
                                "request middleware returned a response")
        
        return request

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 2 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 2 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 9 months, 2 weeks ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 10 months, 1 week ago
  5. Help text hyperlinks by sa2812 11 months ago

Comments

jsdalton (on December 20, 2010):

Nice work on this, btw.

You should note, btw that Simon's original RequestFactory is now part of the django.test.client module. The Test Client actually implements his RequestFactory now to generate the request object and then executes it against the view.

I'm not sure when it was introduced btw, but I'm running the trunk right now. It looks like there have been some additional enhancements since Simon first posted the snippet.

You might want to refactor this to extend the RequestFactory that's now in Django, since they do not appear to have any middleware handling on it as you have created. You can probably achieve your revision in about 5 lines of code I'd imagine.

Cheers.

#

Please login first before commenting.