I'm testing my view for handling invalid form data. In my test case I'm submitting form with missing field and expect view to handle it by displaying error message. Here is a relevant snippet from clean
in my form:
def clean(self):
first_name = self.cleaned_data.get('first_name', '')
last_name = self.cleaned_data.get('last_name', '')
if not first_name or not last_name:
print('Form is invalid')
# This is always executed.
raise ValidationError('All fields are required.')
# other stuff
ValidationError
is always raised, however, form.is_valid()
returns True
nonetheless:
form = forms.EditProfileForm(request.POST, instance=user)
if form.is_valid():
print('Form is valid')
# Update user data.
# Always executed even though error was raised.
This leads to test failing, since I'm asserting that form validation will fail:
def test_invalid_data(self):
formdata = {
'first_name': 'Bruno',
'last_name': '', # Missing data.
'email': 'bruno@schulz.pl',
'password': 'metamorphosis'
}
request = self.factory.post('/accounts/profile', formdata)
request.user = self.user
setup_messages(request)
response = ProfileView.as_view()(request)
self.assertEqual(response.status_code, 200)
self.assertNotEqual(self.user.first_name, formdata['first_name']) # Fails.
self.assertNotEqual(self.user.last_name, formdata['last_name'])
self.assertNotEqual(self.user.email, formdata['email'])
self.assertNotEqual(self.user.username, formdata['email'])
Form validation works properly on a live server (tested "by hand").
It looks like ValidationError
is ignored during TestCase
evaluation.
.Form is invalid
F..Form is valid
.
======================================================================
FAIL: test_invalid_data (.tests.ProfileTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/apps/accounts/tests.py", line 114, in test_invalid_data
self.assertNotEqual(self.user.first_name, formdata['first_name'])
AssertionError: 'Bruno' == 'Bruno'
You haven't shown your full view, but usually you do return redirect('/success-url/')
after a successful post. If your validation error was ignored, then the view would redirect with status code 302, and your test would fail on the earlier line self.assertEqual(response.status_code, 200)
You can access the form from the view with form = response.context['form']
. If you check form.is_valid()
or form.errors
in your test, you will see that your ValidationError
has not been ignored.
Your issue is that your assertNotEqual
checks are not testing what you think they are. When you validate a model form, the instance is modified. If you want to check whether the user has been modified in the database, you need to refresh it from the database first .
self.user.refresh_from_db()
Try using self.add_error('last_name', your_validation_error)
instead of just raising the error:
def clean(self):
first_name = self.cleaned_data.get('first_name', '')
last_name = self.cleaned_data.get('last_name', '')
if not first_name:
print('Form is invalid: missing first name')
# define but don't raise the error
missing_first_name = ValidationError('First name field is required.')
self.add_error('first_name', missing_first_name)
if not last_name:
print('Form is invalid: missing last name')
# define but don't raise error
missing_last_name = ValidationError('Last name field is required.')
self.add_error('last_name', missing_last_name)
# you could also add a string instead of an Error, but a ValidationError is recommended:
# self.add_error('last_name', 'the last name field is missing')
# other stuff
Now form.is_valid()
will return False.
This SO answer led me to the solution, and here are the add_error docs . You should be adding the error to the form with self.add_error
, not raising the validation error.
(I did find this example in the docs where the error is raised instead of passed to self.add_error
, which may be the source of your confusion, but that was for cleaning a specific field. It was not the form.clean()
method. I am assuming you could catch that error and then add it with self.add_error
... but that is a different problem to solve. The point is, I didn't see examples in the docs where form.clean()
should raise the ValidationError. It should add it to the form instead.)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.