summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaptiste Mispelon <bmispelon@gmail.com>2022-02-14 11:02:33 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-02-15 07:15:44 +0100
commitd84cd91e90cb0871e43f98cba8c53be99053e903 (patch)
tree2e8337022d486161d796554b73642c08de527d6c
parent9bb13def5d416ff3d5d1928a2def5babac0e19f6 (diff)
Refs #33348 -- Improved messages raised by SimpleTestCase.assertFormError()/assertFormsetErrors().
This makes messages use BaseFormSet/BaseForm.__repr__() instead of context, and adds the _assert_form_error() helper.
-rw-r--r--django/contrib/admin/helpers.py4
-rw-r--r--django/test/testcases.py147
-rw-r--r--tests/test_client_regress/tests.py61
-rw-r--r--tests/test_utils/tests.py130
4 files changed, 130 insertions, 212 deletions
diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py
index 9c78e758f0..cc5317199d 100644
--- a/django/contrib/admin/helpers.py
+++ b/django/contrib/admin/helpers.py
@@ -84,6 +84,10 @@ class AdminForm:
return self.form.non_field_errors
@property
+ def fields(self):
+ return self.form.fields
+
+ @property
def is_bound(self):
return self.form.is_bound
diff --git a/django/test/testcases.py b/django/test/testcases.py
index a29b77c277..1acc39fd76 100644
--- a/django/test/testcases.py
+++ b/django/test/testcases.py
@@ -563,6 +563,28 @@ class SimpleTestCase(unittest.TestCase):
"the Django test Client."
)
+ def _assert_form_error(self, form, field, errors, msg_prefix, form_repr):
+ if not form.is_bound:
+ self.fail(
+ f"{msg_prefix} The {form_repr} is not bound, it will never have any "
+ f"errors."
+ )
+
+ if field is not None and field not in form.fields:
+ self.fail(
+ f"{msg_prefix}The {form_repr} does not contain the field {field!r}."
+ )
+ if field is None:
+ field_errors = form.non_field_errors()
+ failure_message = f"The non-field errors of {form_repr} don't match."
+ else:
+ field_errors = form.errors.get(field, [])
+ failure_message = (
+ f"The errors of field {field!r} on {form_repr} don't match."
+ )
+
+ self.assertEqual(field_errors, errors, msg_prefix + failure_message)
+
def assertFormError(self, response, form, field, errors, msg_prefix=""):
"""
Assert that a form used to render the response has a specific field
@@ -593,53 +615,11 @@ class SimpleTestCase(unittest.TestCase):
# Search all contexts for the error.
found_form = False
for i, context in enumerate(contexts):
- if form not in context:
- continue
- if not context[form].is_bound:
- form_repr = repr(context[form])
- self.fail(
- f"{msg_prefix}The form {form_repr} is not bound, it will never "
- f"have any errors."
+ if form in context:
+ found_form = True
+ self._assert_form_error(
+ context[form], field, errors, msg_prefix, "form %r" % context[form]
)
- found_form = True
- for err in errors:
- if field:
- if field in context[form].errors:
- field_errors = context[form].errors[field]
- self.assertTrue(
- err in field_errors,
- msg_prefix + "The field '%s' on form '%s' in"
- " context %d does not contain the error '%s'"
- " (actual errors: %s)"
- % (field, form, i, err, repr(field_errors)),
- )
- elif field in context[form].fields:
- self.fail(
- msg_prefix
- + (
- "The field '%s' on form '%s' in context %d contains no "
- "errors"
- )
- % (field, form, i)
- )
- else:
- self.fail(
- msg_prefix
- + (
- "The form '%s' in context %d does not contain the "
- "field '%s'"
- )
- % (form, i, field)
- )
- else:
- non_field_errors = context[form].non_field_errors()
- self.assertTrue(
- err in non_field_errors,
- msg_prefix + "The form '%s' in context %d does not"
- " contain the non-field error '%s'"
- " (actual errors: %s)"
- % (form, i, err, non_field_errors or "none"),
- )
if not found_form:
self.fail(
msg_prefix + "The form '%s' was not used to render the response" % form
@@ -701,64 +681,23 @@ class SimpleTestCase(unittest.TestCase):
f"{msg_prefix}The formset {formset_repr} only has "
f"{form_count} {form_or_forms}."
)
- for err in errors:
- if field is not None:
- if field in context[formset].forms[form_index].errors:
- field_errors = context[formset].forms[form_index].errors[field]
- self.assertTrue(
- err in field_errors,
- msg_prefix + "The field '%s' on formset '%s', "
- "form %d in context %d does not contain the "
- "error '%s' (actual errors: %s)"
- % (field, formset, form_index, i, err, repr(field_errors)),
- )
- elif field in context[formset].forms[form_index].fields:
- self.fail(
- msg_prefix
- + (
- "The field '%s' on formset '%s', form %d in context "
- "%d contains no errors"
- )
- % (field, formset, form_index, i)
- )
- else:
- self.fail(
- msg_prefix
- + (
- "The formset '%s', form %d in context %d does not "
- "contain the field '%s'"
- )
- % (formset, form_index, i, field)
- )
- elif form_index is not None:
- non_field_errors = (
- context[formset].forms[form_index].non_field_errors()
- )
- self.assertFalse(
- not non_field_errors,
- msg_prefix + "The formset '%s', form %d in context %d "
- "does not contain any non-field errors."
- % (formset, form_index, i),
- )
- self.assertTrue(
- err in non_field_errors,
- msg_prefix + "The formset '%s', form %d in context %d "
- "does not contain the non-field error '%s' (actual errors: %s)"
- % (formset, form_index, i, err, repr(non_field_errors)),
- )
- else:
- non_form_errors = context[formset].non_form_errors()
- self.assertFalse(
- not non_form_errors,
- msg_prefix + "The formset '%s' in context %d does not "
- "contain any non-form errors." % (formset, i),
- )
- self.assertTrue(
- err in non_form_errors,
- msg_prefix + "The formset '%s' in context %d does not "
- "contain the non-form error '%s' (actual errors: %s)"
- % (formset, i, err, repr(non_form_errors)),
- )
+ if form_index is not None:
+ form_repr = f"form {form_index} of formset {formset_repr}"
+ self._assert_form_error(
+ context[formset].forms[form_index],
+ field,
+ errors,
+ msg_prefix,
+ form_repr,
+ )
+ else:
+ failure_message = (
+ f"{msg_prefix}The non-form errors of formset {formset_repr} don't "
+ f"match."
+ )
+ self.assertEqual(
+ context[formset].non_form_errors(), errors, failure_message
+ )
if not found_formset:
self.fail(
msg_prefix
diff --git a/tests/test_client_regress/tests.py b/tests/test_client_regress/tests.py
index 11f63f8731..43cc9580cc 100644
--- a/tests/test_client_regress/tests.py
+++ b/tests/test_client_regress/tests.py
@@ -651,7 +651,11 @@ class AssertFormErrorTests(SimpleTestCase):
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "Invalid POST Template")
- msg = "The form 'form' in context 0 does not contain the field 'some_field'"
+ msg = (
+ "The form <TestForm bound=True, valid=False, "
+ "fields=(text;email;value;single;multi)> does not contain the field "
+ "'some_field'."
+ )
with self.assertRaisesMessage(AssertionError, msg):
self.assertFormError(response, "form", "some_field", "Some error.")
with self.assertRaisesMessage(AssertionError, "abc: " + msg):
@@ -672,7 +676,10 @@ class AssertFormErrorTests(SimpleTestCase):
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "Invalid POST Template")
- msg = "The field 'value' on form 'form' in context 0 contains no errors"
+ msg = (
+ "The errors of field 'value' on form <TestForm bound=True, valid=False, "
+ "fields=(text;email;value;single;multi)> don't match."
+ )
with self.assertRaisesMessage(AssertionError, msg):
self.assertFormError(response, "form", "value", "Some error.")
with self.assertRaisesMessage(AssertionError, "abc: " + msg):
@@ -694,9 +701,8 @@ class AssertFormErrorTests(SimpleTestCase):
self.assertTemplateUsed(response, "Invalid POST Template")
msg = (
- "The field 'email' on form 'form' in context 0 does not contain "
- "the error 'Some error.' (actual errors: ['Enter a valid email "
- "address.'])"
+ "The errors of field 'email' on form <TestForm bound=True, valid=False, "
+ "fields=(text;email;value;single;multi)> don't match."
)
with self.assertRaisesMessage(AssertionError, msg):
self.assertFormError(response, "form", "email", "Some error.")
@@ -722,8 +728,8 @@ class AssertFormErrorTests(SimpleTestCase):
self.assertTemplateUsed(response, "Invalid POST Template")
msg = (
- "The form 'form' in context 0 does not contain the non-field "
- "error 'Some error.' (actual errors: none)"
+ "The non-field errors of form <TestForm bound=True, valid=False, "
+ "fields=(text;email;value;single;multi)> don't match."
)
with self.assertRaisesMessage(AssertionError, msg):
self.assertFormError(response, "form", None, "Some error.")
@@ -801,9 +807,8 @@ class AssertFormsetErrorTests(SimpleTestCase):
"An assertion is raised if the field name is unknown"
for prefix, kwargs in self.msg_prefixes:
msg = (
- prefix
- + "The formset 'my_formset', form 0 in context 0 does not contain the "
- "field 'Some_field'"
+ f"{prefix}The form 0 of formset <TestFormFormSet: bound=True "
+ f"valid=False total_forms=2> does not contain the field 'Some_field'."
)
with self.assertRaisesMessage(AssertionError, msg):
self.assertFormsetError(
@@ -819,9 +824,8 @@ class AssertFormsetErrorTests(SimpleTestCase):
"An assertion is raised if the field doesn't have any errors"
for prefix, kwargs in self.msg_prefixes:
msg = (
- prefix
- + "The field 'value' on formset 'my_formset', form 1 in context 0 "
- "contains no errors"
+ f"{prefix}The errors of field 'value' on form 1 of formset "
+ f"<TestFormFormSet: bound=True valid=False total_forms=2> don't match."
)
with self.assertRaisesMessage(AssertionError, msg):
self.assertFormsetError(
@@ -836,10 +840,9 @@ class AssertFormsetErrorTests(SimpleTestCase):
def test_unknown_error(self):
"An assertion is raised if the field doesn't contain the specified error"
for prefix, kwargs in self.msg_prefixes:
- msg = prefix + (
- "The field 'email' on formset 'my_formset', form 0 "
- "in context 0 does not contain the error 'Some error.' "
- "(actual errors: ['Enter a valid email address.'])"
+ msg = (
+ f"{prefix}The errors of field 'email' on form 0 of formset "
+ f"<TestFormFormSet: bound=True valid=False total_forms=2> don't match."
)
with self.assertRaisesMessage(AssertionError, msg):
self.assertFormsetError(
@@ -866,9 +869,8 @@ class AssertFormsetErrorTests(SimpleTestCase):
"""
for prefix, kwargs in self.msg_prefixes:
msg = (
- prefix
- + "The formset 'my_formset', form 1 in context 0 does not contain any "
- "non-field errors."
+ f"{prefix}The non-field errors of form 1 of formset <TestFormFormSet: "
+ f"bound=True valid=False total_forms=2> don't match."
)
with self.assertRaisesMessage(AssertionError, msg):
self.assertFormsetError(
@@ -886,10 +888,9 @@ class AssertFormsetErrorTests(SimpleTestCase):
the provided error.
"""
for prefix, kwargs in self.msg_prefixes:
- msg = prefix + (
- "The formset 'my_formset', form 0 in context 0 does not "
- "contain the non-field error 'Some error.' (actual errors: "
- "['Non-field error.'])"
+ msg = (
+ f"{prefix}The non-field errors of form 0 of formset <TestFormFormSet: "
+ f"bound=True valid=False total_forms=2> don't match."
)
with self.assertRaisesMessage(AssertionError, msg):
self.assertFormsetError(
@@ -923,9 +924,8 @@ class AssertFormsetErrorTests(SimpleTestCase):
"""
for prefix, kwargs in self.msg_prefixes:
msg = (
- prefix
- + "The formset 'my_formset' in context 0 does not contain any non-form "
- "errors."
+ f"{prefix}The non-form errors of formset <TestFormFormSet: bound=True "
+ f"valid=False total_forms=2> don't match"
)
with self.assertRaisesMessage(AssertionError, msg):
self.assertFormsetError(
@@ -943,10 +943,9 @@ class AssertFormsetErrorTests(SimpleTestCase):
the provided error.
"""
for prefix, kwargs in self.msg_prefixes:
- msg = prefix + (
- "The formset 'my_formset' in context 0 does not contain the "
- "non-form error 'Some error.' (actual errors: ['Forms in a set "
- "must have distinct email addresses.'])"
+ msg = (
+ f"{prefix}The non-form errors of formset <TestFormFormSet: bound=True "
+ f"valid=False total_forms=2> don't match"
)
with self.assertRaisesMessage(AssertionError, msg):
self.assertFormsetError(
diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py
index 038e79732b..506773b712 100644
--- a/tests/test_utils/tests.py
+++ b/tests/test_utils/tests.py
@@ -1404,46 +1404,33 @@ class AssertFormErrorTests(SimpleTestCase):
self.assertFormError(response, "form", "field", "invalid value")
def test_field_not_in_form(self):
- msg = "The form 'form' in context 0 does not contain the field 'other_field'"
+ msg = (
+ "The form <TestForm bound=True, valid=False, fields=(field)> does not "
+ "contain the field 'other_field'."
+ )
response = mock.Mock(context=[{"form": TestForm.invalid()}])
with self.assertRaisesMessage(AssertionError, msg):
self.assertFormError(response, "form", "other_field", "invalid value")
- def test_field_not_in_form_multicontext(self):
- msg = "The form 'form' in context 1 does not contain the field 'other_field'"
- response = mock.Mock(context=[{}, {"form": TestForm.invalid()}])
- with self.assertRaisesMessage(AssertionError, msg):
- self.assertFormError(response, "form", "other_field", "invalid value")
-
def test_field_with_no_errors(self):
- msg = "The field 'field' on form 'form' in context 0 contains no errors"
+ msg = (
+ "The errors of field 'field' on form <TestForm bound=True, valid=True, "
+ "fields=(field)> don't match."
+ )
response = mock.Mock(context=[{"form": TestForm.valid()}])
- with self.assertRaisesMessage(AssertionError, msg):
- self.assertFormError(response, "form", "field", "invalid value")
-
- def test_field_with_no_errors_multicontext(self):
- msg = "The field 'field' on form 'form' in context 1 contains no errors"
- response = mock.Mock(context=[{}, {"form": TestForm.valid()}])
- with self.assertRaisesMessage(AssertionError, msg):
+ with self.assertRaisesMessage(AssertionError, msg) as ctx:
self.assertFormError(response, "form", "field", "invalid value")
+ self.assertIn("[] != ['invalid value']", str(ctx.exception))
def test_field_with_different_error(self):
msg = (
- "The field 'field' on form 'form' in context 0 does not contain "
- "the error 'other error' (actual errors: ['invalid value'])"
+ "The errors of field 'field' on form <TestForm bound=True, valid=False, "
+ "fields=(field)> don't match."
)
response = mock.Mock(context=[{"form": TestForm.invalid()}])
- with self.assertRaisesMessage(AssertionError, msg):
- self.assertFormError(response, "form", "field", "other error")
-
- def test_field_with_different_error_multicontext(self):
- msg = (
- "The field 'field' on form 'form' in context 1 does not contain "
- "the error 'other error' (actual errors: ['invalid value'])"
- )
- response = mock.Mock(context=[{}, {"form": TestForm.invalid()}])
- with self.assertRaisesMessage(AssertionError, msg):
+ with self.assertRaisesMessage(AssertionError, msg) as ctx:
self.assertFormError(response, "form", "field", "other error")
+ self.assertIn("['invalid value'] != ['other error']", str(ctx.exception))
def test_basic_positive_assertion(self):
response = mock.Mock(context=[{"form": TestForm.invalid()}])
@@ -1467,8 +1454,14 @@ class AssertFormErrorTests(SimpleTestCase):
self.assertFormError(response, "form", "field", [])
def test_empty_errors_invalid_form(self):
+ msg = (
+ "The errors of field 'field' on form <TestForm bound=True, valid=False, "
+ "fields=(field)> don't match."
+ )
response = mock.Mock(context=[{"form": TestForm.invalid()}])
- self.assertFormError(response, "form", "field", [])
+ with self.assertRaisesMessage(AssertionError, msg) as ctx:
+ self.assertFormError(response, "form", "field", [])
+ self.assertIn("['invalid value'] != []", str(ctx.exception))
def test_non_field_errors(self):
response = mock.Mock(context=[{"form": TestForm.invalid(nonfield=True)}])
@@ -1476,17 +1469,22 @@ class AssertFormErrorTests(SimpleTestCase):
@ignore_warnings(category=RemovedInDjango50Warning)
def test_errors_none(self):
+ msg = (
+ "The errors of field 'field' on form <TestForm bound=True, valid=False, "
+ "fields=(field)> don't match."
+ )
response = mock.Mock(context=[{"form": TestForm.invalid()}])
- self.assertFormError(response, "form", "field", None)
+ with self.assertRaisesMessage(AssertionError, msg):
+ self.assertFormError(response, "form", "field", None)
def test_errors_none_warning(self):
- response = mock.Mock(context=[{"form": TestForm.invalid()}])
+ response = mock.Mock(context=[{"form": TestForm.valid()}])
msg = (
"Passing errors=None to assertFormError() is deprecated, use "
"errors=[] instead."
)
with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
- self.assertFormError(response, "form", "value", None)
+ self.assertFormError(response, "form", "field", None)
class AssertFormsetErrorTests(SimpleTestCase):
@@ -1520,8 +1518,8 @@ class AssertFormsetErrorTests(SimpleTestCase):
def test_field_not_in_form(self):
msg = (
- "The formset 'formset', form 0 in context 0 does not contain the "
- "field 'other_field'"
+ "The form 0 of formset <TestFormset: bound=True valid=False total_forms=1> "
+ "does not contain the field 'other_field'."
)
response = mock.Mock(context=[{"formset": TestFormset.invalid()}])
with self.assertRaisesMessage(AssertionError, msg):
@@ -1533,58 +1531,25 @@ class AssertFormsetErrorTests(SimpleTestCase):
"invalid value",
)
- def test_field_not_in_form_multicontext(self):
- msg = (
- "The formset 'formset', form 0 in context 1 does not contain the "
- "field 'other_field'"
- )
- response = mock.Mock(context=[{}, {"formset": TestFormset.invalid()}])
- with self.assertRaisesMessage(AssertionError, msg):
- self.assertFormsetError(
- response,
- "formset",
- 0,
- "other_field",
- "invalid value",
- )
-
def test_field_with_no_errors(self):
msg = (
- "The field 'field' on formset 'formset', form 0 in context 0 "
- "contains no errors"
+ "The errors of field 'field' on form 0 of formset <TestFormset: bound=True "
+ "valid=True total_forms=1> don't match."
)
response = mock.Mock(context=[{"formset": TestFormset.valid()}])
- with self.assertRaisesMessage(AssertionError, msg):
- self.assertFormsetError(response, "formset", 0, "field", "invalid value")
-
- def test_field_with_no_errors_multicontext(self):
- msg = (
- "The field 'field' on formset 'formset', form 0 in context 1 "
- "contains no errors"
- )
- response = mock.Mock(context=[{}, {"formset": TestFormset.valid()}])
- with self.assertRaisesMessage(AssertionError, msg):
+ with self.assertRaisesMessage(AssertionError, msg) as ctx:
self.assertFormsetError(response, "formset", 0, "field", "invalid value")
+ self.assertIn("[] != ['invalid value']", str(ctx.exception))
def test_field_with_different_error(self):
msg = (
- "The field 'field' on formset 'formset', form 0 in context 0 does"
- " not contain the error 'other error' (actual errors: ['invalid "
- "value'])"
+ "The errors of field 'field' on form 0 of formset <TestFormset: bound=True "
+ "valid=False total_forms=1> don't match."
)
response = mock.Mock(context=[{"formset": TestFormset.invalid()}])
- with self.assertRaisesMessage(AssertionError, msg):
- self.assertFormsetError(response, "formset", 0, "field", "other error")
-
- def test_field_with_different_error_multicontext(self):
- msg = (
- "The field 'field' on formset 'formset', form 0 in context 1 does"
- " not contain the error 'other error' (actual errors: ['invalid "
- "value'])"
- )
- response = mock.Mock(context=[{}, {"formset": TestFormset.invalid()}])
- with self.assertRaisesMessage(AssertionError, msg):
+ with self.assertRaisesMessage(AssertionError, msg) as ctx:
self.assertFormsetError(response, "formset", 0, "field", "other error")
+ self.assertIn("['invalid value'] != ['other error']", str(ctx.exception))
def test_basic_positive_assertion(self):
response = mock.Mock(context=[{"formset": TestFormset.invalid()}])
@@ -1608,8 +1573,14 @@ class AssertFormsetErrorTests(SimpleTestCase):
self.assertFormsetError(response, "formset", 0, "field", [])
def test_empty_errors_invalid_formset(self):
+ msg = (
+ "The errors of field 'field' on form 0 of formset <TestFormset: bound=True "
+ "valid=False total_forms=1> don't match."
+ )
response = mock.Mock(context=[{}, {"formset": TestFormset.invalid()}])
- self.assertFormsetError(response, "formset", 0, "field", [])
+ with self.assertRaisesMessage(AssertionError, msg) as ctx:
+ self.assertFormsetError(response, "formset", 0, "field", [])
+ self.assertIn("['invalid value'] != []", str(ctx.exception))
def test_non_field_errors(self):
response = mock.Mock(
@@ -1670,11 +1641,16 @@ class AssertFormsetErrorTests(SimpleTestCase):
@ignore_warnings(category=RemovedInDjango50Warning)
def test_errors_none(self):
+ msg = (
+ "The errors of field 'field' on form 0 of formset <TestFormset: bound=True "
+ "valid=False total_forms=1> don't match."
+ )
response = mock.Mock(context=[{"formset": TestFormset.invalid()}])
- self.assertFormsetError(response, "formset", 0, "field", None)
+ with self.assertRaisesMessage(AssertionError, msg):
+ self.assertFormsetError(response, "formset", 0, "field", None)
def test_errors_none_warning(self):
- response = mock.Mock(context=[{"formset": TestFormset.invalid()}])
+ response = mock.Mock(context=[{"formset": TestFormset.valid()}])
msg = (
"Passing errors=None to assertFormsetError() is deprecated, use "
"errors=[] instead."