zar3bski
zar3bski

Reputation: 3171

Django: test TemplateView based views triggered by url pattern?

Say I have the following url

path('clients/by_<str:order>', BrowseClients.as_view(), name='browse_clients')

and its corresponding view

@method_decorator(login_required, name='dispatch')
class BrowseClients(TemplateView):

    template_name = "console/browse_clients.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['clients'] = Client.objects.filter(
            owner=self.request.user.id).order_by(self.kwargs["order"])
        context['form'] = AddClientForm()
        return context

How can I test what is in the context?

class TestBrowseClientsView(TestCase, GeneralViewTest):
    fixtures = ['users.yaml', 'clients.yaml']

    def setUp(self):
        self.request = RequestFactory().get('/console/clients/by_inscription')
        self.request.user = User.objects.get(pk=1)

    def test_return_client_ordered_by_inscription_date(self): 
        view = BrowseClients()
        view.setup(self.request)
        context = view.get_context_data()

Naively, I thought that view.setup(self.request) would "feed" .get_context_data() with the relevant kwargs based on the pattern found in self.request. But it does not seem to be the case.

======================================================================
ERROR: test_return_client_ordered_by_inscription_date (console.tests.TestBrowseClientsView)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/src/jengu/console/tests.py", line 164, in test_return_client_ordered_by_inscription_date
    context = view.get_context_data()
  File "/usr/src/jengu/console/views.py", line 34, in get_context_data
    owner=self.request.user.id).order_by(self.kwargs["order"])
KeyError: 'order'

----------------------------------------------------------------------

Why is that the case? I managed to fix my problem by passing status and order explicitly but it looks a bit ad hoc:

def get_context_data(self, status, order, **kwargs):
    def test_return_clients_ordered_by_parameter(self): 
        view = BrowseClients()
        view.setup(self.request)
        context = view.get_context_data("all", "inscription")

Among the different options mentioned here, which one is the more canonical? Am I taking a wrong path, explicitly using variables when defining get_context_data()?

Upvotes: 0

Views: 579

Answers (2)

Alasdair
Alasdair

Reputation: 308849

If you use the test client it will take care of running middleware and initialising the view.

When you use setup() and call the view directly, the URL handler does not run, so it's up to you to pass the kwargs.

def test_return_client_ordered_by_inscription_date(self): 
    view = BrowseClients()
    view.setup(self.request, order='inscription')
    context = view.get_context_data()

Upvotes: 0

KrazyMax
KrazyMax

Reputation: 959

If you want to check what will be in the context of a response, first you need to work with a response object (and you are not, you are just making an instance of your view, not getting the response generated by the view). I don't know about RequestFactory, but I'm sure you'll find out how to adapt my answer to your use case.

So, it would be something like:

def test_your_context(self):
    user = User.objects.get(pk=1)
    self.client.force_login(user) # because of the login_required decorator
    response = self.client.get(reverse("browse_clients"))
    assert response.context['your_context_key'] == "Anything you want to check"

Just a few things to go further:

  • the definition of your get_context_data method seems ok to me,
  • if you use Class Based View, I would recommand you to use also a Base view if you want to check if user is logged in or not (LoginRequiredMixin)
  • you gave a name to your url, so just use it instead of writing its raw form (that's what I did in my answer).

Upvotes: 3

Related Questions