Search code examples
djangodjango-formsdjango-testingdjango-tests

Django Invalidate Form Test If Extra Field Supplied


I have had some issue where a leak of User variables onto the registration form allowed users to set these on user creation.

Can I ensure through testing that this will not be possible again?

Let's say for example I don't want it to be possible that users can set their own 'coupon_code'. How would I test for that?

Accounts/forms.py:

from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import User

class RegisterUserForm(UserCreationForm):
    email = forms.EmailField(required=True, help_text='Required.')

    class Meta(UserCreationForm.Meta):
        model = User
        fields = ('username', 'password1', 'password2', 'email')
        exclude = ('coupon_code',)

Accounts/tests/test_forms.py:

from django.test import TestCase

from Accounts.forms import RegisterUserForm, UpdateUserForm

# Create your tests here.
class RegisterUserFormTest(TestCase):
    #@classmethod
    #def setUpTestData(cls):
    # Set up non-modified objects used by all test methods
    def valid_data(self):
        return {'username':'abc', 'email':'[email protected]', 'password1': 'test123hello', 'password2':'test123hello'}

    def test_register_user_form_cannot_set_coupon_code(self):
        data = self.valid_data()
        data['coupon_code'] = '42'
        form = RegisterUserForm(data=data)
        self.assertFalse(form.is_valid())

Currently the above test fails, as the form is considered valid, even though excluded field is present


Solution

  • From what I understand, the is_valid() method ignores extra data passed to Form. If is_valid() it returns True, that only means data was valid for the prescribed fields, and only those fields will be in the cleaned_data dictionary (Django docs about this).

    I think the test you want to perform must be done on the view function that uses this form. It could look like this:

    from django.test import Client
    
    def test_your_user_creation_view(self):
    
        c = Client()
    
        c.post(reverse(<your view name>),<valid data with 'coupon_code':42>)
    
        new_user = User.objects.get(username='abc')
    
        self.assertTrue(new_user.coupon_code != '42')
        self.assertEqual(new_user.coupon_code,<your default value for coupon_code>)