pythondjangounit-testingdjango-tests

Django tests not isolated when testing authentication


I am testing my authentication with the django.test.Client and two tests cases fail because once I test my test_login_success test case, the other tests fail because the user remains authenticated, even when I am instantiating a new client in the class setUp and even deleting the user in the tearDown.

My code:

from django.test import Client, TestCase

from app.users.models import User


class TestLogin(TestCase):

    def setUp(self):
        super().setUp()
        self.email = 'test@test.com'
        self.password = 'SomeRandomPass96'
        User.objects.create_user(email=self.email, password=self.password)
        self.client = Client()

    def tearDown(self):
        User.objects.filter(email=self.email).delete()
        super().tearDown()

    def test_not_authenticated(self):  # success the first time, fails after test_login_success is executed for the first time.
        user = User.objects.get(email=self.email)
        assert not user.is_authenticated

    def test_login_success(self):  # always success
        self.client.post(
            '/users/login/',
            {'email': self.email, 'password': self.password}
        )
    
        user = User.objects.get(email=self.email)
        assert user.is_authenticated

    def test_login_wrong_credentials(self):  # success the first time, fails after test_login_success is executed for the first time.
        self.client.post(
            '/users/login/',
            {'email': self.email, 'password': 'wrongPassword123'}
        )

        user = User.objects.get(email=self.email)
        assert not user.is_authenticated

Solution

  • The error: user.is_authenticated is not doing what is expected in this code. Since the user in request object in the view will be an AnonymousUser or a User instance depending on the case if it's authenticated and I was accessing directly to a User instance from the database.

    The proper way is to access to the user from the request object, and since we don't have the view context in the test case, Django provides it returned in the response like so:

    def test_not_authenticated(self):
        response = self.client.get('')
        user = response.wsgi_request.user
        assert not user.is_authenticated