Search code examples
pythondjangotdddjango-testingdjango-tests

Setting HttpReferrer In Unit Tests


In my view.py I have the following check on several consecutive pages:

if(request.META.get('HTTP_REFERER') != request.build_absolute_uri(reverse('page1'))):
            return redirect('page1')

This is performed on every page, checking that the user was redirected from the previous page, so (for example), if a user tries to enter the url for page4 in the address bar, the test will fail and he will be sent to page3, then that pages test will fail and he will fall back to page2, and so on.

Im doing this because I have several pages linked together which users must visit consecutively.

The problem comes when I want to unit test. The following test would throw an error because it fails the redirect test and therefore cannot test the logic of the page which im trying to test:

def test_user_information_updated_on_validation_success(self):
        user = User.objects.create_superuser('username')
        self.client.force_login(user)

        self.client.post(reverse('page_4'), {
            'exampleQuestion': 'exampleAnswer'
        })
        user.refresh_from_db()

        self.assertEqual(user.exampleform.somefield, 'exampleAnswer')

How can I access the page within a unit test as if it had been redirected.

Thank you.


Solution

  • A request in the test client accepts keywords that are mapped to WSGI environment variables. Environment variables that start with HTTP and are all uppercase, with dashes mapped to underscores - are Http headers, so the short version is that we can set HTTP headers as such:

    # Wrong: Generates absolute paths without hosts
    self.client.post(
        reverse('page_4'), {'exampleQuestion': 'exampleAnswer'},
        HTTP_REFERER=reverse('page_3')
    )
    

    Edit: It's a little too simple, because HTTP referrers are fully qualified, so we need:

    
    referer = 'http://testserver{}'.format(reverse('page_3'))
    self.client.post(
        reverse('page_4'), {'exampleQuestion': 'exampleAnswer'},
        HTTP_REFERER=referer
    )
    

    FYI: The protocol (wsgi.scheme) and host name (HTTP_SERVER) come from djang.test.client.RequestFactory._base_environ(). If you use a modified client that changes servername and/or protocol, you should adjust accordingly. In that case it would be wise to override _base_environ in your modified test client and derive values from that.