Search code examples
djangohttp-redirectdjango-testing

Testing login redirect


I am trying to write a test to see if my login redirects to the correct page. At the moment I am using this code which isn't working:

class TestAuth(TestCase):
    def setUp(self):
        self.client = Client()

    @classmethod
    def setUpTestData(cls):
        user_login = get_user_model().objects.create(username='admin', email='[email protected]', password='asdf1234')

        cls.user_login = user_login

    def test_login_redirect(self):
        response = self.client.post(
            reverse('udt:login'),
            {
                'username': 'admin',
                'password': 'asdf1234'
            }
        )

        self.assertRedirects(response, reverse('udt:table_list'))

where udt:login equates to '/udt/accounts/login/' and udt:table_list equates to '/udt/table/'.

The login functionality is Django's built-in login with a custom template. When I run the test I get the following error:

AssertionError: 200 != 302 : Response didn't redirect as expected: Response code was 200 (expected 302)

However, when I actually test the login functionality in the app I get this:

[2017/05/30 14:43:22] HTTP POST /udt/accounts/login/ 302 [0.13, 127.0.0.1:60127]
[2017/05/30 14:43:22] HTTP GET /udt/table/ 200 [0.15, 127.0.0.1:60127]

which to me seems like it is in fact redirecting correctly.

So, my question is what is wrong with my test that is causing the assertion error? I am pretty new to testing in Django so it could just be something that I am missing, but it seems like the test should be passing to me.

Any help with this would be much appreciated.

UPDATE

The login template looks like this (just took the standard Django login template and added some bootstrap class names to it):

{% load bootstrap3 %}

<form id="login-form" method="post" action="{% url 'udt:login' %}">
    {% csrf_token %}
    <table class="table">
        <tr>
            <td><label for="id_username">Username</label></td>
            <td><input id="id_username" name="username" type="text" class="form-control"></td>
        </tr>
        <tr>
            <td><label for="id_password">Password</label></td>
            <td><input id="id_password" name="password" type="password" class="form-control"></td>
        </tr>
    </table>
    {% if form.errors %}
        <p class=" label label-danger">
            Your username and password didn't match.
            Please try again.
        </p>
    {% endif %}
    <input type="submit" value="Login" class="btn btn-primary pull-right" />
    <input type="hidden" name="next" value="{{ next }}" />
</form>

url for login looks like so:

url(r'^login/$', auth_views.login, {'template_name': 'auth/login.html'}, name='login')

I am using Django v.1.11.1.


Solution

  • You are creating the user incorrectly. You should use create_user instead of create(), so that the password is correctly hashed.

    @classmethod
    def setUpTestData(cls):
        user_login = get_user_model().objects.create_user(username='admin', email='[email protected]', password='asdf1234')
    

    As an aside, you can remove your setUp method as it is unnecessary. Django's TestCase class takes care of setting up self.client for you.

    One more thing - your URL pattern is fine for Django 1.11, but you could update it to use LoginView to be compatible with Django 2.1+:

    url(r'^login/$', auth_views.LoginView.as_view(template_name= 'auth/login.html'), name='login'),