Search code examples
djangodjango-testing

Testing request.resolver_match in a Django context_processor


I have a Django context processor that puts the name of the current URL into the template context:

def url_name(request):
    url_name = False
    if request.resolver_match:
        url_name = request.resolver_match.url_name
    return {"url_name": url_name}

This works - if I visit / then {{ url_name }} in the template will display "home" because I have a URL pattern like:

path("", HomeView.as_view(), name="home"),

I would like to write a unittest for this context processor. I could do it like this:

from django.test import Client, RequestFactory, TestCase
from myapp.context_processors import url_name

class URLNameTestCase(TestCase):
    def test_url_name(self):
        response = Client().get("/")
        self.assertEqual(response.context["url_name"], "home")

That succeeds, but I'd like to unitttest the url_name() method on its own, outside of the response cycle.

I've tried this:

class URLNameTestCase(TestCase):
    def test_url_name(self):
        request = RequestFactory().get("/")
        context = url_name(request)
        self.assertEqual(context["url_name"], "home")

But that fails because, in this situation, within url_name(), request.resolver_match is None. Why is that?


Solution

  • since you try to get urlname by urlpath you should link your request with some view, you can do it to set "resolver_match" attribute like that:

    from django.urls import resolve
    
    ...
    
    class URLNameTestCase(TestCase):
        def test_url_name(self):
            request = RequestFactory().get("/")
            request.resolver_match = resolve("/")
    ...
    

    You create a request using a RequestFactory but it doesn't mean that your request is linked with any view, to link your request with some view you need to set resolver_match to your request.

    Read more:

    Link 1

    Link 2