Test fails with AssertionError: 302 != 200

I’m trying to add a test that will pass when a logged in user visits a detail view of their profile page.

If I runserver and manually visit the page, I get a 200 response. However, the test fails because it returns a 302 response.

Questions

  • I’m not sure why it’s redirecting in the test but not if I visit the URL in the browser. Any ideas?
  • My hypothesis was that I was doing something wrong with logging in and therefore it was redirecting to a login page. This is why I put print(self.client)in the test to see what’d come out (I think it printing out the object you see from the test output confirms I am successfully logging in—is that true?)
  • I’m not sure how to find out more information (e.g. how would I find out where the 302 is redirecting to during the test?)

As always, any help is appreciated, and code/error below:

profiles/tests/tests.py

from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse

from accounts.tests.factories import CustomUserFactory


class TestUserProfileViews(TestCase):
    def test_userprofile_detailview_authenticated_superuser(self):
        authenticated_superuser = CustomUserFactory.create(
            username="authenticatedsuperuser",
            password="secret",
            is_staff=True,
            is_superuser=True,
        )

        self.client.login(username="authenticatedsuperuser", password="secret")
        print(self.client)
        no_response = self.client.get("/profiles/1234/")
        response = self.client.get(
            reverse(
                "user_profile_detail",
                kwargs={"pk": authenticated_superuser.userprofile.id},
            )
        )

        self.assertEqual(response.status_code, 200)
        self.assertEqual(no_response.status_code, 404)
        self.assertTemplateUsed(response, "user_profile_detail.html")

profiles/tests/factories.py

import factory

from ..models import UserProfile
from accounts.tests.factories import CustomUserFactory


class UserProfileFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = UserProfile

    user = factory.SubFactory(CustomUserFactory)

    @factory.post_generation
    def following(self, create, extracted):
        if not create or not extracted:
            return
        self.following.add(*extracted)

accounts/tests/factories.py

import factory

from ..models import CustomUser


class CustomUserFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = CustomUser

    username = "username123"
    password = "password456"

    class Params:
        with_first_name = factory.Trait(first_name="firstname")
        with_last_name = factory.Trait(last_name="lastname")
        with_email = factory.Trait(email="email@email.com")

profiles/urls.py

from django.urls import path

from .views import UserProfileDetailView

urlpatterns = [
    path("<uuid:pk>/", UserProfileDetailView.as_view(), name="user_profile_detail"),
]

profiles/views.py

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import DetailView

from .models import UserProfile


class UserProfileDetailView(LoginRequiredMixin, DetailView):
    model = UserProfile
    context_object_name = "profile"
    template_name = "user_profile_detail.html"

‘pytest profiles -rP’ output

========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.10.7, pytest-8.2.0, pluggy-1.5.0
django: version: 5.0.6, settings: aa_django_project.settings (from ini)
rootdir: /Users/stephaniegoulet/Desktop/code/Hummingbird
configfile: pytest.ini
plugins: factoryboy-2.5.1, Faker-25.1.0, django-4.8.0
collected 1 item                                                                                                                                                                                       

profiles/tests/tests.py F                                                                                                                                                                        [100%]

=============================================================================================== FAILURES ===============================================================================================
_______________________________________________________________ TestUserProfileViews.test_userprofile_detailview_authenticated_superuser _______________________________________________________________

self = <profiles.tests.tests.TestUserProfileViews testMethod=test_userprofile_detailview_authenticated_superuser>

    def test_userprofile_detailview_authenticated_superuser(self):
        authenticated_superuser = CustomUserFactory.create(
            username="authenticatedsuperuser",
            password="secret",
            is_staff=True,
            is_superuser=True,
        )
    
        self.client.login(username="authenticatedsuperuser", password="secret")
        print(self.client)
        no_response = self.client.get("/profiles/1234/")
        response = self.client.get(
            reverse(
                "user_profile_detail",
                kwargs={"pk": authenticated_superuser.userprofile.id},
            )
        )
    
>       self.assertEqual(response.status_code, 200)
E       AssertionError: 302 != 200

profiles/tests/tests.py:76: AssertionError
----------------------------------------------------------------------------------------- Captured stdout call -----------------------------------------------------------------------------------------
<django.test.client.Client object at 0x110a07940>
------------------------------------------------------------------------------------------ Captured log call -------------------------------------------------------------------------------------------
WARNING  django.request:log.py:241 Not Found: /profiles/1234/
========================================================================================== 1 failed in 0.85s ===========================================================================================

runserver output for visiting profile detail view when logged in

% python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
May 14, 2024 - 19:45:48
Django version 5.0.6, using settings 'aa_django_project.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

[14/May/2024 19:45:55] "GET /profiles/2d13b0e6-eaf6-46b8-83c1-c47be3f80e41/ HTTP/1.1" 200 2962
[14/May/2024 19:45:55] "GET /static/css/base.css HTTP/1.1" 304 0
[14/May/2024 19:45:55] "GET /static/js/base.js HTTP/1.1" 304 0

Hi,

I believe your issue has to do with the way your CustomUserFactory is defined. Can you check that self.client.login(...) in your test actually returns True?

self.assertTrue(self.client.login(username="authenticatedsuperuser", password="secret"))

As far as I know, factory_boy will use the create() method of the model’s manager to create instances, which means that your CustomUserFactory.create(...) call in your test eventually becomes CustomUser.objects.create(...) and that doesn’t actually work for creating a user with a username/password (because of password hashing).

Instead you should be using CustomUser.objects.create_user(...).

One way to do this with factory_boy is have a custom _create() method on your factory class that calls the right method on the manager: Common recipes — Factory Boy stable documentation

I hope that helps

2 Likes

What specifically is the data type of the id field in your CustomUserModel? (Can you verify that the pk of authenticatedsuperuser is actually a UUID?)

Thanks so much, @bmispelon - I had a few misunderstandings before which tripped me up but now I’ve learned something new :grin:

@KenWhitesell - just to answer your question anyway for any potential future readers: The CustomUser model doesn’t have a UUID, but it has a 1:1 relationship with the Profile model which does have a UUIDField set as the id

1 Like