djangodjango-class-based-viewsdjango-testingdjango-3.2

Django CBV - How to test get_context_data with uuid in url?


I use the UUID in the url instead of the primary key. I assume, but am not sure, that this is the cause of my problem in testing my CBVs.

my view for user profile :

class ProfileView(DetailView):
    slug_url_kwarg = 'uuid'
    slug_field = 'uuid'

    model = User
    template_name = 'users/profile.html'
    context_object_name = 'user_profile'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['uuid'] = self.kwargs.get("uuid")
        return context

My url :

path(
    route='profile/<uuid:uuid>',
    view=views.ProfileView.as_view(),
    name='profile',
),

I can't test get_context_data, Django tells me that my view has no "object" attribute. Maybe I need to override get_object, but my search didn't find anything.

My test :

class BaseTest(TestCase):
    def setUp(self):
        # Set up non-modified objects used by all test methods
        self.factory = RequestFactory()
        self.user2 = User.objects.create_user(
            email='caroline.dupont@free.fr',
            password='fhh456GG455t',
            status='VALIDATED',
            )
    
        return super().setUp()

    def profile_view_instance(self, test_user):
        request = self.factory.get(reverse('profile', args=(test_user.uuid,)))
        request.user = test_user
        view = ProfileView()
        view.setup(request)
    
        return view

class ProfileViewTestCase(BaseTest):

    def test_get_context_data(self):
        self.client.force_login(self.user2)
        context = self.profile_view_instance(self.user2).get_context_data()
        self.assertIn('uuid', context)

The error :

ERROR: test_get_context_data (tests.appusers.test_views.ProfileViewTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\Developpement\projet13\tests\appusers\test_views.py", line 75, in test_get_context_data
    context = self.profile_view_instance(self.user2).get_context_data()
  File "D:\Developpement\projet13\users\views.py", line 66, in get_context_data
    context = super().get_context_data(**kwargs)
  File "D:\Developpement\projet13\venvp13\lib\site-packages\django\views\generic\detail.py", line 94, in get_context_data
if self.object:
AttributeError: 'ProfileView' object has no attribute 'object'

Solution

  • The profile_view_instance is not sufficient: a DetailView has some boilerplate logic in the .get(…) method that is necessary to run before the .get_context_data(…) will be triggered. It is also not a good idea to implement this logic in the test function, since then you duplicate logic, and it will be painful to update it each time you update the Django version.

    Django has created a client that can be used to trigger a view. You can define a test with:

    class ProfileViewTestCase(BaseTest):
    
        def test_get_context_data(self):
            self.client.force_login(self.user2)
            response = self.client.get(f'/profile/{self.user2.uuid}')
            context = response.context
            self.assertIn('uuid', context)