[PYTHON] [Django] Test standard LoginForm [TDD]

How do I test LoginForm when I'm trying to test it in Django ... How do I test it in a pseudonym ...? I made a test while thinking, so I will leave a memo as a memorandum.

environment

version
python 3.7.4
Django 2.2.5

The test uses the Django standard one (Is it called ʻunit test`?).

What to test

First think about what to test. In conclusion, I decided to test the following:

--Does an error occur if the user name is different? --Does an error occur if the password is different? -Is there an error when inputting correctly?

These are the above three. I'll list below what I was thinking about, but I'll also mention why I didn't test it.

What you want to test Why not test
Form validation(Unusable characters)check All you need is when you register as a user(If you can't register, you can't log in)
Check if you can log in Doesn't it seem like you can't test your login because you have a CSRF token?
client.Login check using login I'm not using form so I don't think it's necessary

That's it. When I read it back, I feel that LoginForm and LoginView are messed up. However, since LoginView uses only LoginForm, I think that it is only necessary to test Forms.

Views and Forms code

This is the Forms to be tested and the Views code used.

Views.py


from django.contrib.auth.views import LoginView
from ..forms import LoginForm

class Login(LoginView):
    form_class = LoginForm
    template_name = 'account_management/login.html'
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs) #First call the inherited method
        context["username"] = self.request.user.username
        return context

Views.py


from django.contrib.auth.forms import AuthenticationForm

class LoginForm(AuthenticationForm):
    """Login form"""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs['class'] = 'form-control'
            field.widget.attrs['placeholder'] = field.label  #Put the label of the field in the placeholder

Write test code

Now let's write the test code for the above Forms. test will be described in tests.py. (If you have changed the directory, please read as appropriate.) Class names and method names must start with test. The code is below.

Views.py


from django.test import TestCase
from django.contrib.auth.models import User
from ..forms import LoginForm

class Test_LoginForm(TestCase):

    def setUp(self):
        User.objects.create_user(username='test_account', email='[email protected]', password='test_pass') 
   
    def test_LoginForm_name_error(self):
        form_data = {
            'username': 'error',
            'password': 'test_pass'
        }
        form = LoginForm(data=form_data)
        self.assertFalse(form.is_valid(), 'There was no correct error with the user name.')
    
    def test_LoginForm_pass_error(self):
        form_data = {
            'username': 'test_account',
            'password': 'error'
        }
        form = LoginForm(data=form_data)
        self.assertFalse(form.is_valid(), 'The password did not give an error correctly.')

    def test_LoginForm_true(self):
        form_data = {
            'username': 'test_account',
            'password': 'test_pass'
        }
        form = LoginForm(data=form_data)
        self.assertTrue(form.is_valid(), 'The form did not work properly.')

Let's take a look inside the class. setUp will be executed just before the method in the class is executed. Django's tests recreate the DB for each test, so you need to define the user each time. So, this time, I'm defining the user in setUp.

Next are each test method. There is no big difference between the three, so I will explain them together. In LoginForm, you can enter your user name and password, and if they are correct, you can log in. form_data describes what to pass in which field in dictionary type. Then pass the data to LoginForm.

If the passed value is correct with the registered user name and password pair (because you are logged in this time), form.is_valid () will return True. Otherwise, it returns False.

This time, the above two methods are supposed to return an error, that is, they are expecting False. self.assertFalse (form.is_valid (),'The password did not give a correct error.') Is written. If you expect True, it will be ʻassert True. The arguments of ʻassertFalse are the value to evaluate and the display in case of an error.

When you do this,

$ python manage.py test account_management/tests -k
Using existing test database for alias 'default'...
System check identified no issues (0 silenced).
...
----------------------------------------------------------------------
Ran 4 tests in 3.196s

OK
Preserving test database for alias 'default'...

You can see that the test passed like this. The command -k is an option that does not delete the DB created in the test, but uses the next one as well. I wanted to check the DB after execution, so I attached it and executed it.

Summary

I don't know if it matches, but I was able to write a test for the time being. For some reason it took me a day to get to this. I hope this will allow you to create subsequent tests smoothly ...

Recommended Posts

[Django] Test standard LoginForm [TDD]
Django test
[Django] How to test Form [TDD]
Test standard output with Pytest
[Django] I wanted to test when POSTing a large file [TDD]
Test Driven Development with Django Part 4
Test Driven Development with Django Part 6
Test Driven Development with Django Part 2
[Test Driven Development (TDD)] Chapter 21 Summary
Test Driven Development with Django Part 1
Test Driven Development with Django Part 5