summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMads Jensen <mje@inducks.org>2017-05-28 21:37:21 +0200
committerTim Graham <timograham@gmail.com>2017-07-29 19:07:23 -0400
commita51c4de1945be2225f20fad794cfb52d8f1f9236 (patch)
tree36386b70a27cf027a8a491de319c3e59e0d3d0cd
parent38988f289f7f5708f5ea85de2d5dfe0d86b23106 (diff)
Used assertRaisesMessage() to test Django's error messages.
-rw-r--r--tests/admin_registration/tests.py6
-rw-r--r--tests/admin_utils/tests.py2
-rw-r--r--tests/aggregation_regress/tests.py34
-rw-r--r--tests/apps/tests.py6
-rw-r--r--tests/auth_tests/test_auth_backends.py12
-rw-r--r--tests/auth_tests/test_basic.py9
-rw-r--r--tests/auth_tests/test_management.py5
-rw-r--r--tests/basic/tests.py20
-rw-r--r--tests/bulk_create/tests.py3
-rw-r--r--tests/check_framework/tests.py3
-rw-r--r--tests/custom_columns/tests.py6
-rw-r--r--tests/custom_lookups/tests.py8
-rw-r--r--tests/custom_managers/tests.py9
-rw-r--r--tests/custom_pk/tests.py2
-rw-r--r--tests/delete/tests.py6
-rw-r--r--tests/delete_regress/tests.py5
-rw-r--r--tests/distinct_on_fields/tests.py8
-rw-r--r--tests/expressions/tests.py9
-rw-r--r--tests/flatpages_tests/test_templatetags.py18
-rw-r--r--tests/force_insert_update/tests.py9
-rw-r--r--tests/foreign_object/tests.py14
-rw-r--r--tests/forms_tests/field_tests/test_uuidfield.py3
-rw-r--r--tests/forms_tests/tests/test_formsets.py3
-rw-r--r--tests/forms_tests/tests/tests.py6
-rw-r--r--tests/generic_relations/tests.py7
-rw-r--r--tests/generic_views/test_base.py6
-rw-r--r--tests/generic_views/test_dates.py6
-rw-r--r--tests/generic_views/test_detail.py6
-rw-r--r--tests/generic_views/test_edit.py19
-rw-r--r--tests/generic_views/test_list.py6
-rw-r--r--tests/get_earliest_or_latest/tests.py6
-rw-r--r--tests/i18n/patterns/tests.py3
-rw-r--r--tests/lookup/tests.py17
-rw-r--r--tests/m2m_regress/tests.py2
-rw-r--r--tests/many_to_many/tests.py6
-rw-r--r--tests/many_to_one/tests.py12
-rw-r--r--tests/migrations/test_commands.py15
-rw-r--r--tests/migrations/test_operations.py2
-rw-r--r--tests/model_fields/test_decimalfield.py3
-rw-r--r--tests/model_fields/test_floatfield.py5
-rw-r--r--tests/model_forms/tests.py26
-rw-r--r--tests/model_inheritance/test_abstract_inheritance.py5
-rw-r--r--tests/model_inheritance/tests.py12
-rw-r--r--tests/multiple_database/tests.py58
-rw-r--r--tests/null_queries/tests.py5
-rw-r--r--tests/one_to_one/tests.py6
-rw-r--r--tests/prefetch_related/tests.py24
-rw-r--r--tests/queries/tests.py8
-rw-r--r--tests/redirects_tests/tests.py6
-rw-r--r--tests/reverse_lookup/tests.py6
-rw-r--r--tests/select_for_update/tests.py6
-rw-r--r--tests/select_related/tests.py4
-rw-r--r--tests/settings_tests/tests.py2
-rw-r--r--tests/sitemaps_tests/test_http.py8
-rw-r--r--tests/staticfiles_tests/test_finders.py7
-rw-r--r--tests/syndication_tests/tests.py6
-rw-r--r--tests/template_tests/syntax_tests/i18n/test_blocktrans.py8
-rw-r--r--tests/template_tests/syntax_tests/test_filter_syntax.py11
-rw-r--r--tests/template_tests/syntax_tests/test_with.py5
-rw-r--r--tests/template_tests/test_parser.py6
-rw-r--r--tests/test_utils/tests.py19
-rw-r--r--tests/timezones/tests.py12
-rw-r--r--tests/transaction_hooks/tests.py3
-rw-r--r--tests/transactions/tests.py13
-rw-r--r--tests/update/tests.py3
-rw-r--r--tests/update_only_fields/tests.py10
-rw-r--r--tests/urlpatterns_reverse/tests.py7
-rw-r--r--tests/user_commands/tests.py5
-rw-r--r--tests/validators/tests.py3
69 files changed, 448 insertions, 173 deletions
diff --git a/tests/admin_registration/tests.py b/tests/admin_registration/tests.py
index 125d8eae61..8601328647 100644
--- a/tests/admin_registration/tests.py
+++ b/tests/admin_registration/tests.py
@@ -30,7 +30,8 @@ class TestRegistration(SimpleTestCase):
def test_prevent_double_registration(self):
self.site.register(Person)
- with self.assertRaises(admin.sites.AlreadyRegistered):
+ msg = 'The model Person is already registered'
+ with self.assertRaisesMessage(admin.sites.AlreadyRegistered, msg):
self.site.register(Person)
def test_registration_with_star_star_options(self):
@@ -55,7 +56,8 @@ class TestRegistration(SimpleTestCase):
Exception is raised when trying to register an abstract model.
Refs #12004.
"""
- with self.assertRaises(ImproperlyConfigured):
+ msg = 'The model Location is abstract, so it cannot be registered with admin.'
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
self.site.register(Location)
def test_is_registered_model(self):
diff --git a/tests/admin_utils/tests.py b/tests/admin_utils/tests.py
index 09136ea72a..1f475c2f5b 100644
--- a/tests/admin_utils/tests.py
+++ b/tests/admin_utils/tests.py
@@ -222,7 +222,7 @@ class UtilsTests(SimpleTestCase):
"article"
)
- with self.assertRaises(AttributeError):
+ with self.assertRaisesMessage(AttributeError, "Unable to lookup 'unknown' on Article"):
label_for_field("unknown", Article)
def test_callable(obj):
diff --git a/tests/aggregation_regress/tests.py b/tests/aggregation_regress/tests.py
index 7dc9a95688..91e993a6d1 100644
--- a/tests/aggregation_regress/tests.py
+++ b/tests/aggregation_regress/tests.py
@@ -431,13 +431,23 @@ class AggregationTests(TestCase):
def test_field_error(self):
# Bad field requests in aggregates are caught and reported
- with self.assertRaises(FieldError):
+ msg = (
+ "Cannot resolve keyword 'foo' into field. Choices are: authors, "
+ "contact, contact_id, hardbackbook, id, isbn, name, pages, price, "
+ "pubdate, publisher, publisher_id, rating, store, tags"
+ )
+ with self.assertRaisesMessage(FieldError, msg):
Book.objects.all().aggregate(num_authors=Count('foo'))
- with self.assertRaises(FieldError):
+ with self.assertRaisesMessage(FieldError, msg):
Book.objects.all().annotate(num_authors=Count('foo'))
- with self.assertRaises(FieldError):
+ msg = (
+ "Cannot resolve keyword 'foo' into field. Choices are: authors, "
+ "contact, contact_id, hardbackbook, id, isbn, name, num_authors, "
+ "pages, price, pubdate, publisher, publisher_id, rating, store, tags"
+ )
+ with self.assertRaisesMessage(FieldError, msg):
Book.objects.all().annotate(num_authors=Count('authors__id')).aggregate(Max('foo'))
def test_more(self):
@@ -738,19 +748,25 @@ class AggregationTests(TestCase):
def test_duplicate_alias(self):
# Regression for #11256 - duplicating a default alias raises ValueError.
- with self.assertRaises(ValueError):
+ msg = (
+ "The named annotation 'authors__age__avg' conflicts with "
+ "the default name for another annotation."
+ )
+ with self.assertRaisesMessage(ValueError, msg):
Book.objects.all().annotate(Avg('authors__age'), authors__age__avg=Avg('authors__age'))
def test_field_name_conflict(self):
# Regression for #11256 - providing an aggregate name
# that conflicts with a field name on the model raises ValueError
- with self.assertRaises(ValueError):
+ msg = "The annotation 'age' conflicts with a field on the model."
+ with self.assertRaisesMessage(ValueError, msg):
Author.objects.annotate(age=Avg('friends__age'))
def test_m2m_name_conflict(self):
# Regression for #11256 - providing an aggregate name
# that conflicts with an m2m name on the model raises ValueError
- with self.assertRaises(ValueError):
+ msg = "The annotation 'friends' conflicts with a field on the model."
+ with self.assertRaisesMessage(ValueError, msg):
Author.objects.annotate(friends=Count('friends'))
def test_values_queryset_non_conflict(self):
@@ -778,7 +794,8 @@ class AggregationTests(TestCase):
def test_reverse_relation_name_conflict(self):
# Regression for #11256 - providing an aggregate name
# that conflicts with a reverse-related name on the model raises ValueError
- with self.assertRaises(ValueError):
+ msg = "The annotation 'book_contact_set' conflicts with a field on the model."
+ with self.assertRaisesMessage(ValueError, msg):
Author.objects.annotate(book_contact_set=Avg('friends__age'))
def test_pickle(self):
@@ -937,7 +954,8 @@ class AggregationTests(TestCase):
# Regression for #10766 - Shouldn't be able to reference an aggregate
# fields in an aggregate() call.
- with self.assertRaises(FieldError):
+ msg = "Cannot compute Avg('mean_age'): 'mean_age' is an aggregate"
+ with self.assertRaisesMessage(FieldError, msg):
Book.objects.annotate(mean_age=Avg('authors__age')).annotate(Avg('mean_age'))
def test_empty_filter_count(self):
diff --git a/tests/apps/tests.py b/tests/apps/tests.py
index 50b3927434..2910220b94 100644
--- a/tests/apps/tests.py
+++ b/tests/apps/tests.py
@@ -53,7 +53,8 @@ class AppsTests(SimpleTestCase):
"""
Tests when INSTALLED_APPS contains an incorrect app config.
"""
- with self.assertRaises(ImproperlyConfigured):
+ msg = "'apps.apps.BadConfig' must supply a name attribute."
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
with self.settings(INSTALLED_APPS=['apps.apps.BadConfig']):
pass
@@ -61,7 +62,8 @@ class AppsTests(SimpleTestCase):
"""
Tests when INSTALLED_APPS contains a class that isn't an app config.
"""
- with self.assertRaises(ImproperlyConfigured):
+ msg = "'apps.apps.NotAConfig' isn't a subclass of AppConfig."
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
with self.settings(INSTALLED_APPS=['apps.apps.NotAConfig']):
pass
diff --git a/tests/auth_tests/test_auth_backends.py b/tests/auth_tests/test_auth_backends.py
index ea9ddd426c..744f8ad817 100644
--- a/tests/auth_tests/test_auth_backends.py
+++ b/tests/auth_tests/test_auth_backends.py
@@ -445,7 +445,11 @@ class NoBackendsTest(TestCase):
self.user = User.objects.create_user('test', 'test@example.com', 'test')
def test_raises_exception(self):
- with self.assertRaises(ImproperlyConfigured):
+ msg = (
+ 'No authentication backends have been defined. '
+ 'Does AUTHENTICATION_BACKENDS contain anything?'
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
self.user.has_perm(('perm', TestObj()))
@@ -626,7 +630,11 @@ class ImproperlyConfiguredUserModelTest(TestCase):
request = HttpRequest()
request.session = self.client.session
- with self.assertRaises(ImproperlyConfigured):
+ msg = (
+ "AUTH_USER_MODEL refers to model 'thismodel.doesntexist' "
+ "that has not been installed"
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
get_user(request)
diff --git a/tests/auth_tests/test_basic.py b/tests/auth_tests/test_basic.py
index b2c70faffb..80a56f8ca3 100644
--- a/tests/auth_tests/test_basic.py
+++ b/tests/auth_tests/test_basic.py
@@ -97,13 +97,18 @@ class BasicTestCase(TestCase):
@override_settings(AUTH_USER_MODEL='badsetting')
def test_swappable_user_bad_setting(self):
"The alternate user setting must point to something in the format app.model"
- with self.assertRaises(ImproperlyConfigured):
+ msg = "AUTH_USER_MODEL must be of the form 'app_label.model_name'"
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
get_user_model()
@override_settings(AUTH_USER_MODEL='thismodel.doesntexist')
def test_swappable_user_nonexistent_model(self):
"The current user model must point to an installed model"
- with self.assertRaises(ImproperlyConfigured):
+ msg = (
+ "AUTH_USER_MODEL refers to model 'thismodel.doesntexist' "
+ "that has not been installed"
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
get_user_model()
def test_user_verbose_names_translatable(self):
diff --git a/tests/auth_tests/test_management.py b/tests/auth_tests/test_management.py
index c4368b3bcf..c43091d932 100644
--- a/tests/auth_tests/test_management.py
+++ b/tests/auth_tests/test_management.py
@@ -158,7 +158,8 @@ class ChangepasswordManagementCommandTestCase(TestCase):
A CommandError should be thrown by handle() if the user enters in
mismatched passwords three times.
"""
- with self.assertRaises(CommandError):
+ msg = "Aborting password change for user 'joe' after 3 attempts"
+ with self.assertRaisesMessage(CommandError, msg):
call_command('changepassword', username='joe', stdout=self.stdout, stderr=self.stderr)
@mock.patch.object(changepassword.Command, '_get_pass', return_value='1234567890')
@@ -316,7 +317,7 @@ class CreatesuperuserManagementCommandTestCase(TestCase):
# We skip validation because the temporary substitution of the
# swappable User model messes with validation.
new_io = StringIO()
- with self.assertRaises(CommandError):
+ with self.assertRaisesMessage(CommandError, 'You must use --email with --noinput.'):
call_command(
"createsuperuser",
interactive=False,
diff --git a/tests/basic/tests.py b/tests/basic/tests.py
index d55277c0f2..c44e17dd24 100644
--- a/tests/basic/tests.py
+++ b/tests/basic/tests.py
@@ -335,8 +335,8 @@ class ModelTest(TestCase):
self.assertEqual(article.headline, notlazy)
def test_emptyqs(self):
- # Can't be instantiated
- with self.assertRaises(TypeError):
+ msg = "EmptyQuerySet can't be instantiated"
+ with self.assertRaisesMessage(TypeError, msg):
EmptyQuerySet()
self.assertIsInstance(Article.objects.none(), EmptyQuerySet)
self.assertNotIsInstance('', EmptyQuerySet)
@@ -397,7 +397,8 @@ class ModelTest(TestCase):
def test_hash(self):
# Value based on PK
self.assertEqual(hash(Article(id=1)), hash(1))
- with self.assertRaises(TypeError):
+ msg = 'Model instances without primary key value are unhashable'
+ with self.assertRaisesMessage(TypeError, msg):
# No PK value -> unhashable (because save() would then change
# hash)
hash(Article())
@@ -618,7 +619,7 @@ class SelectOnSaveTests(TestCase):
with self.assertNumQueries(1):
asos.save(force_update=True)
Article.objects.all().delete()
- with self.assertRaises(DatabaseError):
+ with self.assertRaisesMessage(DatabaseError, 'Forced update did not affect any rows.'):
with self.assertNumQueries(1):
asos.save(force_update=True)
@@ -653,9 +654,13 @@ class SelectOnSaveTests(TestCase):
# This is not wanted behavior, but this is how Django has always
# behaved for databases that do not return correct information
# about matched rows for UPDATE.
- with self.assertRaises(DatabaseError):
+ with self.assertRaisesMessage(DatabaseError, 'Forced update did not affect any rows.'):
asos.save(force_update=True)
- with self.assertRaises(DatabaseError):
+ msg = (
+ "An error occurred in the current transaction. You can't "
+ "execute queries until the end of the 'atomic' block."
+ )
+ with self.assertRaisesMessage(DatabaseError, msg):
asos.save(update_fields=['pub_date'])
finally:
Article._base_manager._queryset_class = orig_class
@@ -688,7 +693,8 @@ class ModelRefreshTests(TestCase):
def test_unknown_kwarg(self):
s = SelfRef.objects.create()
- with self.assertRaises(TypeError):
+ msg = "refresh_from_db() got an unexpected keyword argument 'unknown_kwarg'"
+ with self.assertRaisesMessage(TypeError, msg):
s.refresh_from_db(unknown_kwarg=10)
def test_refresh_fk(self):
diff --git a/tests/bulk_create/tests.py b/tests/bulk_create/tests.py
index 6b3e0bedc4..2439050623 100644
--- a/tests/bulk_create/tests.py
+++ b/tests/bulk_create/tests.py
@@ -108,7 +108,8 @@ class BulkCreateTests(TestCase):
"""
valid_country = Country(name='Germany', iso_two_letter='DE')
invalid_country = Country(id=0, name='Poland', iso_two_letter='PL')
- with self.assertRaises(ValueError):
+ msg = 'The database backend does not accept 0 as a value for AutoField.'
+ with self.assertRaisesMessage(ValueError, msg):
Country.objects.bulk_create([valid_country, invalid_country])
def test_batch_same_vals(self):
diff --git a/tests/check_framework/tests.py b/tests/check_framework/tests.py
index 2128da3dc6..abb4298c65 100644
--- a/tests/check_framework/tests.py
+++ b/tests/check_framework/tests.py
@@ -179,7 +179,8 @@ class CheckCommandTests(SimpleTestCase):
@override_system_checks([simple_system_check, tagged_system_check])
def test_invalid_tag(self):
- with self.assertRaises(CommandError):
+ msg = 'There is no system check with the "missingtag" tag.'
+ with self.assertRaisesMessage(CommandError, msg):
call_command('check', tags=['missingtag'])
@override_system_checks([simple_system_check])
diff --git a/tests/custom_columns/tests.py b/tests/custom_columns/tests.py
index 2d7044b8de..f5dfd9c0cd 100644
--- a/tests/custom_columns/tests.py
+++ b/tests/custom_columns/tests.py
@@ -37,7 +37,11 @@ class CustomColumnsTests(TestCase):
)
def test_field_error(self):
- with self.assertRaises(FieldError):
+ msg = (
+ "Cannot resolve keyword 'firstname' into field. Choices are: "
+ "Author_ID, article, first_name, last_name, primary_set"
+ )
+ with self.assertRaisesMessage(FieldError, msg):
Author.objects.filter(firstname__exact="John")
def test_attribute_error(self):
diff --git a/tests/custom_lookups/tests.py b/tests/custom_lookups/tests.py
index 4a477b4687..d39ebe6cdc 100644
--- a/tests/custom_lookups/tests.py
+++ b/tests/custom_lookups/tests.py
@@ -319,7 +319,8 @@ class BilateralTransformTests(TestCase):
def test_bilateral_inner_qs(self):
with register_lookup(models.CharField, UpperBilateralTransform):
- with self.assertRaises(NotImplementedError):
+ msg = 'Bilateral transformations on nested querysets are not supported.'
+ with self.assertRaisesMessage(NotImplementedError, msg):
Author.objects.filter(name__upper__in=Author.objects.values_list('name'))
def test_bilateral_multi_value(self):
@@ -501,13 +502,14 @@ class LookupTransformCallOrderTests(TestCase):
def test_call_order(self):
with register_lookup(models.DateField, TrackCallsYearTransform):
# junk lookup - tries lookup, then transform, then fails
- with self.assertRaises(FieldError):
+ msg = "Unsupported lookup 'junk' for IntegerField or join on the field not permitted."
+ with self.assertRaisesMessage(FieldError, msg):
Author.objects.filter(birthdate__testyear__junk=2012)
self.assertEqual(TrackCallsYearTransform.call_order,
['lookup', 'transform'])
TrackCallsYearTransform.call_order = []
# junk transform - tries transform only, then fails
- with self.assertRaises(FieldError):
+ with self.assertRaisesMessage(FieldError, msg):
Author.objects.filter(birthdate__testyear__junk__more_junk=2012)
self.assertEqual(TrackCallsYearTransform.call_order,
['transform'])
diff --git a/tests/custom_managers/tests.py b/tests/custom_managers/tests.py
index d095036f10..ee2ac1d552 100644
--- a/tests/custom_managers/tests.py
+++ b/tests/custom_managers/tests.py
@@ -58,7 +58,8 @@ class CustomManagerTests(TestCase):
# Methods with queryset_only=False are copied even if they are private.
manager._optin_private_method()
# Methods with queryset_only=True aren't copied even if they are public.
- with self.assertRaises(AttributeError):
+ msg = "%r object has no attribute 'optout_public_method'" % manager.__class__.__name__
+ with self.assertRaisesMessage(AttributeError, msg):
manager.optout_public_method()
def test_manager_use_queryset_methods(self):
@@ -93,7 +94,8 @@ class CustomManagerTests(TestCase):
querysets.
"""
Person.custom_queryset_custom_manager.manager_only()
- with self.assertRaises(AttributeError):
+ msg = "'CustomQuerySet' object has no attribute 'manager_only'"
+ with self.assertRaisesMessage(AttributeError, msg):
Person.custom_queryset_custom_manager.all().manager_only()
def test_queryset_and_manager(self):
@@ -116,7 +118,8 @@ class CustomManagerTests(TestCase):
The default manager, "objects", doesn't exist, because a custom one
was provided.
"""
- with self.assertRaises(AttributeError):
+ msg = "type object 'Book' has no attribute 'objects'"
+ with self.assertRaisesMessage(AttributeError, msg):
Book.objects
def test_filtering(self):
diff --git a/tests/custom_pk/tests.py b/tests/custom_pk/tests.py
index 7c89b6d120..da0cff14cc 100644
--- a/tests/custom_pk/tests.py
+++ b/tests/custom_pk/tests.py
@@ -145,7 +145,7 @@ class BasicCustomPKTests(TestCase):
# Or we can use the real attribute name for the primary key:
self.assertEqual(e.employee_code, 123)
- with self.assertRaises(AttributeError):
+ with self.assertRaisesMessage(AttributeError, "'Employee' object has no attribute 'id'"):
e.id
def test_in_bulk(self):
diff --git a/tests/delete/tests.py b/tests/delete/tests.py
index 0c7e218d38..98467efb6a 100644
--- a/tests/delete/tests.py
+++ b/tests/delete/tests.py
@@ -60,7 +60,11 @@ class OnDeleteTests(TestCase):
def test_protect(self):
a = create_a('protect')
- with self.assertRaises(IntegrityError):
+ msg = (
+ "Cannot delete some instances of model 'R' because they are "
+ "referenced through a protected foreign key: 'A.protect'"
+ )
+ with self.assertRaisesMessage(IntegrityError, msg):
a.protect.delete()
def test_do_nothing(self):
diff --git a/tests/delete_regress/tests.py b/tests/delete_regress/tests.py
index 7472731e94..7f913257ab 100644
--- a/tests/delete_regress/tests.py
+++ b/tests/delete_regress/tests.py
@@ -244,9 +244,10 @@ class ProxyDeleteTest(TestCase):
self.assertEqual(len(FooFileProxy.objects.all()), 0)
def test_19187_values(self):
- with self.assertRaises(TypeError):
+ msg = 'Cannot call delete() after .values() or .values_list()'
+ with self.assertRaisesMessage(TypeError, msg):
Image.objects.values().delete()
- with self.assertRaises(TypeError):
+ with self.assertRaisesMessage(TypeError, msg):
Image.objects.values_list().delete()
diff --git a/tests/distinct_on_fields/tests.py b/tests/distinct_on_fields/tests.py
index 6bb518d2b1..93a332cf83 100644
--- a/tests/distinct_on_fields/tests.py
+++ b/tests/distinct_on_fields/tests.py
@@ -97,16 +97,18 @@ class DistinctOnTests(TestCase):
def test_distinct_not_implemented_checks(self):
# distinct + annotate not allowed
- with self.assertRaises(NotImplementedError):
+ msg = 'annotate() + distinct(fields) is not implemented.'
+ with self.assertRaisesMessage(NotImplementedError, msg):
Celebrity.objects.annotate(Max('id')).distinct('id')[0]
- with self.assertRaises(NotImplementedError):
+ with self.assertRaisesMessage(NotImplementedError, msg):
Celebrity.objects.distinct('id').annotate(Max('id'))[0]
# However this check is done only when the query executes, so you
# can use distinct() to remove the fields before execution.
Celebrity.objects.distinct('id').annotate(Max('id')).distinct()[0]
# distinct + aggregate not allowed
- with self.assertRaises(NotImplementedError):
+ msg = 'aggregate() + distinct(fields) not implemented.'
+ with self.assertRaisesMessage(NotImplementedError, msg):
Celebrity.objects.distinct('id').aggregate(Max('id'))
def test_distinct_on_in_ordered_subquery(self):
diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py
index aa090d2746..8952045002 100644
--- a/tests/expressions/tests.py
+++ b/tests/expressions/tests.py
@@ -246,7 +246,8 @@ class BasicExpressionsTests(TestCase):
)
with transaction.atomic():
- with self.assertRaises(FieldError):
+ msg = "Joined field references are not permitted in this query"
+ with self.assertRaisesMessage(FieldError, msg):
Company.objects.exclude(
ceo__firstname=F('point_of_contact__firstname')
).update(name=F('point_of_contact__lastname'))
@@ -293,13 +294,15 @@ class BasicExpressionsTests(TestCase):
def test():
test_gmbh.point_of_contact = F("ceo")
- with self.assertRaises(ValueError):
+ msg = 'F(ceo)": "Company.point_of_contact" must be a "Employee" instance.'
+ with self.assertRaisesMessage(ValueError, msg):
test()
test_gmbh.point_of_contact = test_gmbh.ceo
test_gmbh.save()
test_gmbh.name = F("ceo__last_name")
- with self.assertRaises(FieldError):
+ msg = 'Joined field references are not permitted in this query'
+ with self.assertRaisesMessage(FieldError, msg):
test_gmbh.save()
def test_object_update_unsaved_objects(self):
diff --git a/tests/flatpages_tests/test_templatetags.py b/tests/flatpages_tests/test_templatetags.py
index 688d85a224..1ce8f65079 100644
--- a/tests/flatpages_tests/test_templatetags.py
+++ b/tests/flatpages_tests/test_templatetags.py
@@ -128,17 +128,21 @@ class FlatpageTemplateTagTests(TestCase):
def render(t):
return Template(t).render(Context())
- with self.assertRaises(TemplateSyntaxError):
+ msg = (
+ "get_flatpages expects a syntax of get_flatpages "
+ "['url_starts_with'] [for user] as context_name"
+ )
+ with self.assertRaisesMessage(TemplateSyntaxError, msg):
render("{% load flatpages %}{% get_flatpages %}")
- with self.assertRaises(TemplateSyntaxError):
+ with self.assertRaisesMessage(TemplateSyntaxError, msg):
render("{% load flatpages %}{% get_flatpages as %}")
- with self.assertRaises(TemplateSyntaxError):
+ with self.assertRaisesMessage(TemplateSyntaxError, msg):
render("{% load flatpages %}{% get_flatpages cheesecake flatpages %}")
- with self.assertRaises(TemplateSyntaxError):
+ with self.assertRaisesMessage(TemplateSyntaxError, msg):
render("{% load flatpages %}{% get_flatpages as flatpages asdf %}")
- with self.assertRaises(TemplateSyntaxError):
+ with self.assertRaisesMessage(TemplateSyntaxError, msg):
render("{% load flatpages %}{% get_flatpages cheesecake user as flatpages %}")
- with self.assertRaises(TemplateSyntaxError):
+ with self.assertRaisesMessage(TemplateSyntaxError, msg):
render("{% load flatpages %}{% get_flatpages for user as flatpages asdf %}")
- with self.assertRaises(TemplateSyntaxError):
+ with self.assertRaisesMessage(TemplateSyntaxError, msg):
render("{% load flatpages %}{% get_flatpages prefix for user as flatpages asdf %}")
diff --git a/tests/force_insert_update/tests.py b/tests/force_insert_update/tests.py
index 2232283cb8..8ffe98ad4f 100644
--- a/tests/force_insert_update/tests.py
+++ b/tests/force_insert_update/tests.py
@@ -20,13 +20,15 @@ class ForceTests(TestCase):
# Won't work because force_update and force_insert are mutually
# exclusive
c.value = 4
- with self.assertRaises(ValueError):
+ msg = 'Cannot force both insert and updating in model saving.'
+ with self.assertRaisesMessage(ValueError, msg):
c.save(force_insert=True, force_update=True)
# Try to update something that doesn't have a primary key in the first
# place.
c1 = Counter(name="two", value=2)
- with self.assertRaises(ValueError):
+ msg = 'Cannot force an update in save() with no primary key.'
+ with self.assertRaisesMessage(ValueError, msg):
with transaction.atomic():
c1.save(force_update=True)
c1.save(force_insert=True)
@@ -40,7 +42,8 @@ class ForceTests(TestCase):
# Trying to update should still fail, even with manual primary keys, if
# the data isn't in the database already.
obj = WithCustomPK(name=1, value=1)
- with self.assertRaises(DatabaseError):
+ msg = 'Forced update did not affect any rows.'
+ with self.assertRaisesMessage(DatabaseError, msg):
with transaction.atomic():
obj.save(force_update=True)
diff --git a/tests/foreign_object/tests.py b/tests/foreign_object/tests.py
index e74732ab72..59d4357802 100644
--- a/tests/foreign_object/tests.py
+++ b/tests/foreign_object/tests.py
@@ -368,7 +368,12 @@ class MultiColumnFKTests(TestCase):
ArticleTag.objects.create(article=a1, name="foo")
self.assertEqual(Article.objects.filter(tag__name="foo").count(), 1)
self.assertEqual(Article.objects.filter(tag__name="bar").count(), 0)
- with self.assertRaises(FieldError):
+ msg = (
+ "Cannot resolve keyword 'tags' into field. Choices are: "
+ "active_translation, active_translation_q, articletranslation, "
+ "id, idea_things, newsarticle, pub_date, tag"
+ )
+ with self.assertRaisesMessage(FieldError, msg):
Article.objects.filter(tags__name="foo")
def test_many_to_many_related_query_name(self):
@@ -377,7 +382,12 @@ class MultiColumnFKTests(TestCase):
a1.ideas.add(i1)
self.assertEqual(Article.objects.filter(idea_things__name="idea1").count(), 1)
self.assertEqual(Article.objects.filter(idea_things__name="idea2").count(), 0)
- with self.assertRaises(FieldError):
+ msg = (
+ "Cannot resolve keyword 'ideas' into field. Choices are: "
+ "active_translation, active_translation_q, articletranslation, "
+ "id, idea_things, newsarticle, pub_date, tag"
+ )
+ with self.assertRaisesMessage(FieldError, msg):
Article.objects.filter(ideas__name="idea1")
@translation.override('fi')
diff --git a/tests/forms_tests/field_tests/test_uuidfield.py b/tests/forms_tests/field_tests/test_uuidfield.py
index 08498ab9c9..ed08efd659 100644
--- a/tests/forms_tests/field_tests/test_uuidfield.py
+++ b/tests/forms_tests/field_tests/test_uuidfield.py
@@ -18,9 +18,8 @@ class UUIDFieldTest(SimpleTestCase):
def test_uuidfield_3(self):
field = UUIDField()
- with self.assertRaises(ValidationError) as cm:
+ with self.assertRaisesMessage(ValidationError, 'Enter a valid UUID.'):
field.clean('550e8400')
- self.assertEqual(cm.exception.messages[0], 'Enter a valid UUID.')
def test_uuidfield_4(self):
field = UUIDField()
diff --git a/tests/forms_tests/tests/test_formsets.py b/tests/forms_tests/tests/test_formsets.py
index 29f138b2d1..defa46b730 100644
--- a/tests/forms_tests/tests/test_formsets.py
+++ b/tests/forms_tests/tests/test_formsets.py
@@ -1338,7 +1338,8 @@ ArticleFormSet = formset_factory(ArticleForm)
class TestIsBoundBehavior(SimpleTestCase):
def test_no_data_raises_validation_error(self):
- with self.assertRaises(ValidationError):
+ msg = 'ManagementForm data is missing or has been tampered with'
+ with self.assertRaisesMessage(ValidationError, msg):
ArticleFormSet({}).is_valid()
def test_with_management_data_attrs_work_fine(self):
diff --git a/tests/forms_tests/tests/tests.py b/tests/forms_tests/tests/tests.py
index 043b8e0edc..a54ad09c26 100644
--- a/tests/forms_tests/tests/tests.py
+++ b/tests/forms_tests/tests/tests.py
@@ -247,7 +247,11 @@ class RelatedModelFormTests(SimpleTestCase):
model = A
fields = '__all__'
- with self.assertRaises(ValueError):
+ msg = (
+ "Cannot create form field for 'ref' yet, because "
+ "its related model 'B' has not been loaded yet"
+ )
+ with self.assertRaisesMessage(ValueError, msg):
ModelFormMetaclass('Form', (ModelForm,), {'Meta': Meta})
class B(models.Model):
diff --git a/tests/generic_relations/tests.py b/tests/generic_relations/tests.py
index 91bb616420..d3aa3b15f8 100644
--- a/tests/generic_relations/tests.py
+++ b/tests/generic_relations/tests.py
@@ -347,7 +347,12 @@ class GenericRelationsTests(TestCase):
def test_generic_relation_related_name_default(self):
# GenericRelation isn't usable from the reverse side by default.
- with self.assertRaises(FieldError):
+ msg = (
+ "Cannot resolve keyword 'vegetable' into field. Choices are: "
+ "animal, content_object, content_type, content_type_id, id, "
+ "manualpk, object_id, tag, valuabletaggeditem"
+ )
+ with self.assertRaisesMessage(FieldError, msg):
TaggedItem.objects.filter(vegetable__isnull=True)
def test_multiple_gfk(self):
diff --git a/tests/generic_views/test_base.py b/tests/generic_views/test_base.py
index 8215e67e1a..1579408712 100644
--- a/tests/generic_views/test_base.py
+++ b/tests/generic_views/test_base.py
@@ -273,7 +273,11 @@ class TemplateViewTest(SimpleTestCase):
"""
A template view must provide a template name.
"""
- with self.assertRaises(ImproperlyConfigured):
+ msg = (
+ "TemplateResponseMixin requires either a definition of "
+ "'template_name' or an implementation of 'get_template_names()'"
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
self.client.get('/template/no_template/')
@require_jinja2
diff --git a/tests/generic_views/test_dates.py b/tests/generic_views/test_dates.py
index 454b9e5a1d..ff3b09ddf3 100644
--- a/tests/generic_views/test_dates.py
+++ b/tests/generic_views/test_dates.py
@@ -79,7 +79,11 @@ class ArchiveIndexViewTests(TestDataMixin, TestCase):
self.assertTemplateUsed(res, 'generic_views/book_detail.html')
def test_archive_view_invalid(self):
- with self.assertRaises(ImproperlyConfigured):
+ msg = (
+ 'BookArchive is missing a QuerySet. Define BookArchive.model, '
+ 'BookArchive.queryset, or override BookArchive.get_queryset().'
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
self.client.get('/dates/books/invalid/')
def test_archive_view_by_month(self):
diff --git a/tests/generic_views/test_detail.py b/tests/generic_views/test_detail.py
index da20db066e..002435dfce 100644
--- a/tests/generic_views/test_detail.py
+++ b/tests/generic_views/test_detail.py
@@ -175,7 +175,11 @@ class DetailViewTest(TestCase):
self.client.get('/detail/author/invalid/url/')
def test_invalid_queryset(self):
- with self.assertRaises(ImproperlyConfigured):
+ msg = (
+ 'AuthorDetail is missing a QuerySet. Define AuthorDetail.model, '
+ 'AuthorDetail.queryset, or override AuthorDetail.get_queryset().'
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
self.client.get('/detail/author/invalid/qs/')
def test_non_model_object_with_meta(self):
diff --git a/tests/generic_views/test_edit.py b/tests/generic_views/test_edit.py
index 3a68fc4098..522189a475 100644
--- a/tests/generic_views/test_edit.py
+++ b/tests/generic_views/test_edit.py
@@ -159,7 +159,11 @@ class CreateViewTests(TestCase):
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe>'])
def test_create_without_redirect(self):
- with self.assertRaises(ImproperlyConfigured):
+ msg = (
+ 'No URL to redirect to. Either provide a url or define a '
+ 'get_absolute_url method on the Model.'
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
self.client.post('/edit/authors/create/naive/', {'name': 'Randall Munroe', 'slug': 'randall-munroe'})
def test_create_restricted(self):
@@ -312,9 +316,11 @@ class UpdateViewTests(TestCase):
name='Randall Munroe',
slug='randall-munroe',
)
- # Should raise exception -- No redirect URL provided, and no
- # get_absolute_url provided
- with self.assertRaises(ImproperlyConfigured):
+ msg = (
+ 'No URL to redirect to. Either provide a url or define a '
+ 'get_absolute_url method on the Model.'
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
self.client.post(
'/edit/author/%d/update/naive/' % a.pk,
{'name': 'Randall Munroe (author of xkcd)', 'slug': 'randall-munroe'}
@@ -404,7 +410,6 @@ class DeleteViewTests(TestCase):
name='Randall Munroe',
slug='randall-munroe',
)
- # Should raise exception -- No redirect URL provided, and no
- # get_absolute_url provided
- with self.assertRaises(ImproperlyConfigured):
+ msg = 'No URL to redirect to. Provide a success_url.'
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
self.client.post('/edit/author/%d/delete/naive/' % a.pk)
diff --git a/tests/generic_views/test_list.py b/tests/generic_views/test_list.py
index 429d46f50c..ea57b6af9a 100644
--- a/tests/generic_views/test_list.py
+++ b/tests/generic_views/test_list.py
@@ -200,7 +200,11 @@ class ListViewTests(TestCase):
self.assertTemplateUsed(res, 'generic_views/author_list.html')
def test_missing_items(self):
- with self.assertRaises(ImproperlyConfigured):
+ msg = (
+ 'AuthorList is missing a QuerySet. Define AuthorList.model, '
+ 'AuthorList.queryset, or override AuthorList.get_queryset().'
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
self.client.get('/list/authors/invalid/')
def test_paginated_list_view_does_not_load_entire_table(self):
diff --git a/tests/get_earliest_or_latest/tests.py b/tests/get_earliest_or_latest/tests.py
index 2322e0a91c..c59f4324f0 100644
--- a/tests/get_earliest_or_latest/tests.py
+++ b/tests/get_earliest_or_latest/tests.py
@@ -118,7 +118,11 @@ class EarliestOrLatestTests(TestCase):
# "get_latest_by" set -- just pass in the field name manually.
Person.objects.create(name="Ralph", birthday=datetime(1950, 1, 1))
p2 = Person.objects.create(name="Stephanie", birthday=datetime(1960, 2, 3))
- with self.assertRaises(AssertionError):
+ msg = (
+ "earliest() and latest() require either a field_name parameter or "
+ "'get_latest_by' in the model"
+ )
+ with self.assertRaisesMessage(AssertionError, msg):
Person.objects.latest()
self.assertEqual(Person.objects.latest("birthday"), p2)
diff --git a/tests/i18n/patterns/tests.py b/tests/i18n/patterns/tests.py
index a1d4269735..0f69f0d8c5 100644
--- a/tests/i18n/patterns/tests.py
+++ b/tests/i18n/patterns/tests.py
@@ -78,7 +78,8 @@ class URLPrefixTests(URLTestCaseBase):
@override_settings(ROOT_URLCONF='i18n.patterns.urls.wrong')
def test_invalid_prefix_use(self):
- with self.assertRaises(ImproperlyConfigured):
+ msg = 'Using i18n_patterns in an included URLconf is not allowed.'
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
reverse('account:register')
diff --git a/tests/lookup/tests.py b/tests/lookup/tests.py
index 289d8dde1b..41270cd19f 100644
--- a/tests/lookup/tests.py
+++ b/tests/lookup/tests.py
@@ -315,7 +315,11 @@ class LookupTests(TestCase):
# However, an exception FieldDoesNotExist will be thrown if you specify
# a nonexistent field name in values() (a field that is neither in the
# model nor in extra(select)).
- with self.assertRaises(FieldError):
+ msg = (
+ "Cannot resolve keyword 'id_plus_two' into field. Choices are: "
+ "author, author_id, headline, id, id_plus_one, pub_date, slug, tag"
+ )
+ with self.assertRaisesMessage(FieldError, msg):
Article.objects.extra(select={'id_plus_one': 'id + 1'}).values('id', 'id_plus_two')
# If you don't specify field names to values(), all are returned.
self.assertSequenceEqual(
@@ -733,11 +737,16 @@ class LookupTests(TestCase):
"""
A lookup query containing non-fields raises the proper exception.
"""
- with self.assertRaises(FieldError):
+ msg = "Unsupported lookup 'blahblah' for CharField or join on the field not permitted."
+ with self.assertRaisesMessage(FieldError, msg):
Article.objects.filter(headline__blahblah=99)
- with self.assertRaises(FieldError):
+ with self.assertRaisesMessage(FieldError, msg):
Article.objects.filter(headline__blahblah__exact=99)
- with self.assertRaises(FieldError):
+ msg = (
+ "Cannot resolve keyword 'blahblah' into field. Choices are: "
+ "author, author_id, headline, id, pub_date, slug, tag"
+ )
+ with self.assertRaisesMessage(FieldError, msg):
Article.objects.filter(blahblah=99)
def test_lookup_collision(self):
diff --git a/tests/m2m_regress/tests.py b/tests/m2m_regress/tests.py
index 6d4a4f02ed..b38ccf83be 100644
--- a/tests/m2m_regress/tests.py
+++ b/tests/m2m_regress/tests.py
@@ -102,7 +102,7 @@ class M2MRegressionTests(TestCase):
c1 = TagCollection.objects.create(name='c1')
c1.tags.set([t1, t2])
- with self.assertRaises(TypeError):
+ with self.assertRaisesMessage(TypeError, "'int' object is not iterable"):
c1.tags.set(7)
c1.refresh_from_db()
diff --git a/tests/many_to_many/tests.py b/tests/many_to_many/tests.py
index d81d88b176..5b1c6e1516 100644
--- a/tests/many_to_many/tests.py
+++ b/tests/many_to_many/tests.py
@@ -29,7 +29,11 @@ class ManyToManyTests(TestCase):
# Create an Article.
a5 = Article(headline='Django lets you reate Web apps easily')
# You can't associate it with a Publication until it's been saved.
- with self.assertRaises(ValueError):
+ msg = (
+ '"<Article: Django lets you reate Web apps easily>" needs to have '
+ 'a value for field "id" before this many-to-many relationship can be used.'
+ )
+ with self.assertRaisesMessage(ValueError, msg):
getattr(a5, 'publications')
# Save it!
a5.save()
diff --git a/tests/many_to_one/tests.py b/tests/many_to_one/tests.py
index 0382a9a45e..aab050234c 100644
--- a/tests/many_to_one/tests.py
+++ b/tests/many_to_one/tests.py
@@ -406,7 +406,8 @@ class ManyToOneTests(TestCase):
self.assertEqual(a3.reporter.id, self.r2.id)
# Get should respect explicit foreign keys as well.
- with self.assertRaises(MultipleObjectsReturned):
+ msg = 'get() returned more than one Article -- it returned 2!'
+ with self.assertRaisesMessage(MultipleObjectsReturned, msg):
Article.objects.get(reporter_id=self.r.id)
self.assertEqual(
repr(a3),
@@ -484,7 +485,11 @@ class ManyToOneTests(TestCase):
setattr(c, "parent", None)
# You also can't assign an object of the wrong type here
- with self.assertRaises(ValueError):
+ msg = (
+ 'Cannot assign "<First: First object (1)>": "Child.parent" must '
+ 'be a "Parent" instance.'
+ )
+ with self.assertRaisesMessage(ValueError, msg):
setattr(c, "parent", First(id=1, second=1))
# You can assign None to Child.parent during object creation.
@@ -550,7 +555,8 @@ class ManyToOneTests(TestCase):
p = Parent.objects.create(name="Parent")
c = Child.objects.create(name="Child", parent=p)
- with self.assertRaises(ValueError):
+ msg = 'Cannot assign "%r": "Child.parent" must be a "Parent" instance.' % c
+ with self.assertRaisesMessage(ValueError, msg):
Child.objects.create(name="Grandchild", parent=c)
def test_fk_instantiation_outside_model(self):
diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py
index 3e4f7b5410..e6aaa8fc90 100644
--- a/tests/migrations/test_commands.py
+++ b/tests/migrations/test_commands.py
@@ -757,8 +757,18 @@ class MakeMigrationsTests(MigrationTestBase):
makemigrations exits if it detects a conflict.
"""
with self.temporary_migration_module(module="migrations.test_migrations_conflict"):
- with self.assertRaises(CommandError):
+ with self.assertRaises(CommandError) as context:
call_command("makemigrations")
+ exception_message = str(context.exception)
+ self.assertIn(
+ 'Conflicting migrations detected; multiple leaf nodes '
+ 'in the migration graph:',
+ exception_message
+ )
+ self.assertIn('0002_second', exception_message)
+ self.assertIn('0002_conflicting_second', exception_message)
+ self.assertIn('in migrations', exception_message)
+ self.assertIn("To fix them run 'python manage.py makemigrations --merge'", exception_message)
def test_makemigrations_merge_no_conflict(self):
"""
@@ -780,7 +790,8 @@ class MakeMigrationsTests(MigrationTestBase):
"""
makemigrations exits if no app is specified with 'empty' mode.
"""
- with self.assertRaises(CommandError):
+ msg = 'You must supply at least one app label when using --empty.'
+ with self.assertRaisesMessage(CommandError, msg):
call_command("makemigrations", empty=True)
def test_makemigrations_empty_migration(self):
diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py
index ec55ab912e..40acd5ed61 100644
--- a/tests/migrations/test_operations.py
+++ b/tests/migrations/test_operations.py
@@ -1945,7 +1945,7 @@ class OperationTests(OperationTestBase):
operation.database_backwards("test_runpython", editor, project_state, new_state)
self.assertEqual(project_state.apps.get_model("test_runpython", "Pony").objects.count(), 0)
# Now test we can't use a string
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, 'RunPython must be supplied with a callable'):
migrations.RunPython("print 'ahahaha'")
# And deconstruction
definition = operation.deconstruct()
diff --git a/tests/model_fields/test_decimalfield.py b/tests/model_fields/test_decimalfield.py
index 17bbae7ffa..c8851c5d94 100644
--- a/tests/model_fields/test_decimalfield.py
+++ b/tests/model_fields/test_decimalfield.py
@@ -21,7 +21,8 @@ class DecimalFieldTests(TestCase):
# Uses default rounding of ROUND_HALF_EVEN.
self.assertEqual(f.to_python(2.0625), Decimal('2.062'))
self.assertEqual(f.to_python(2.1875), Decimal('2.188'))
- with self.assertRaises(ValidationError):
+ msg = "'abc' value must be a decimal number."
+ with self.assertRaisesMessage(ValidationError, msg):
f.to_python('abc')
def test_default(self):
diff --git a/tests/model_fields/test_floatfield.py b/tests/model_fields/test_floatfield.py
index c1c941b25c..481925cf11 100644
--- a/tests/model_fields/test_floatfield.py
+++ b/tests/model_fields/test_floatfield.py
@@ -21,8 +21,7 @@ class TestFloatField(TestCase):
instance.size = instance
msg = (
'Tried to update field model_fields.FloatModel.size with a model '
- 'instance, %r. Use a value '
- 'compatible with FloatField.'
+ 'instance, %r. Use a value compatible with FloatField.'
) % instance
with transaction.atomic():
with self.assertRaisesMessage(TypeError, msg):
@@ -30,5 +29,5 @@ class TestFloatField(TestCase):
# Try setting field to object on retrieved object
obj = FloatModel.objects.get(pk=instance.id)
obj.size = obj
- with self.assertRaises(TypeError):
+ with self.assertRaisesMessage(TypeError, msg):
obj.save()
diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py
index 578ef00696..0cfc18659f 100644
--- a/tests/model_forms/tests.py
+++ b/tests/model_forms/tests.py
@@ -180,7 +180,7 @@ class ModelFormBaseTest(TestCase):
def test_no_model_class(self):
class NoModelModelForm(forms.ModelForm):
pass
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, 'ModelForm has no model class specified.'):
NoModelModelForm()
def test_empty_fields_to_fields_for_model(self):
@@ -326,7 +326,7 @@ class ModelFormBaseTest(TestCase):
fields = ('name', 'age')
def test_extra_field_modelform_factory(self):
- with self.assertRaises(FieldError):
+ with self.assertRaisesMessage(FieldError, 'Unknown field(s) (no-field) specified for Person'):
modelform_factory(Person, fields=['no-field', 'name'])
def test_replace_field(self):
@@ -426,7 +426,8 @@ class ModelFormBaseTest(TestCase):
form = PriceFormWithoutQuantity({'price': '6.00'})
self.assertTrue(form.is_valid())
price = form.save(commit=False)
- with self.assertRaises(ValidationError):
+ msg = "{'quantity': ['This field cannot be null.']}"
+ with self.assertRaisesMessage(ValidationError, msg):
price.full_clean()
# The form should not validate fields that it doesn't contain even if they are
@@ -498,11 +499,12 @@ class ModelFormBaseTest(TestCase):
pass # no model
# Can't create new form
- with self.assertRaises(ValueError):
+ msg = 'ModelForm has no model class specified.'
+ with self.assertRaisesMessage(ValueError, msg):
InvalidModelForm()
# Even if you provide a model instance
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, msg):
InvalidModelForm(instance=Category)
def test_subcategory_form(self):
@@ -1301,10 +1303,11 @@ class ModelFormBasicTests(TestCase):
["Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."]
)
self.assertEqual(f.cleaned_data, {'url': 'foo'})
- with self.assertRaises(ValueError):
+ msg = "The Category could not be created because the data didn't validate."
+ with self.assertRaisesMessage(ValueError, msg):
f.save()
f = BaseCategoryForm({'name': '', 'slug': '', 'url': 'foo'})
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, msg):
f.save()
def test_multi_fields(self):
@@ -1597,7 +1600,8 @@ class ModelChoiceFieldTests(TestCase):
# instantiated. This proves clean() checks the database during clean() rather
# than caching it at time of instantiation.
Category.objects.get(url='4th').delete()
- with self.assertRaises(ValidationError):
+ msg = "['Select a valid choice. That choice is not one of the available choices.']"
+ with self.assertRaisesMessage(ValidationError, msg):
f.clean(c4.id)
def test_modelchoicefield_choices(self):
@@ -3045,7 +3049,11 @@ class LocalizedModelFormTest(TestCase):
self.assertTrue(f.fields['right'].localize)
def test_model_form_refuses_arbitrary_string(self):
- with self.assertRaises(TypeError):
+ msg = (
+ "BrokenLocalizedTripleForm.Meta.localized_fields "
+ "cannot be a string. Did you mean to type: ('foo',)?"
+ )
+ with self.assertRaisesMessage(TypeError, msg):
class BrokenLocalizedTripleForm(forms.ModelForm):
class Meta:
model = Triple
diff --git a/tests/model_inheritance/test_abstract_inheritance.py b/tests/model_inheritance/test_abstract_inheritance.py
index c496ac963b..f03bc3fa7e 100644
--- a/tests/model_inheritance/test_abstract_inheritance.py
+++ b/tests/model_inheritance/test_abstract_inheritance.py
@@ -150,10 +150,11 @@ class AbstractInheritanceTests(TestCase):
def full_name(self):
return self.first_name + self.last_name
- with self.assertRaises(FieldDoesNotExist):
+ msg = "Descendant has no field named %r"
+ with self.assertRaisesMessage(FieldDoesNotExist, msg % 'middle_name'):
Descendant._meta.get_field('middle_name')
- with self.assertRaises(FieldDoesNotExist):
+ with self.assertRaisesMessage(FieldDoesNotExist, msg % 'full_name'):
Descendant._meta.get_field('full_name')
def test_overriding_field_removed_by_concrete_model(self):
diff --git a/tests/model_inheritance/tests.py b/tests/model_inheritance/tests.py
index feff4a1407..e1eca65742 100644
--- a/tests/model_inheritance/tests.py
+++ b/tests/model_inheritance/tests.py
@@ -43,7 +43,7 @@ class ModelInheritanceTests(TestCase):
# However, the CommonInfo class cannot be used as a normal model (it
# doesn't exist as a model).
- with self.assertRaises(AttributeError):
+ with self.assertRaisesMessage(AttributeError, "'CommonInfo' has no attribute 'objects'"):
CommonInfo.objects.all()
def test_reverse_relation_for_different_hierarchy_tree(self):
@@ -51,7 +51,12 @@ class ModelInheritanceTests(TestCase):
# Restaurant object cannot access that reverse relation, since it's not
# part of the Place-Supplier Hierarchy.
self.assertQuerysetEqual(Place.objects.filter(supplier__name="foo"), [])
- with self.assertRaises(FieldError):
+ msg = (
+ "Cannot resolve keyword 'supplier' into field. Choices are: "
+ "address, chef, chef_id, id, italianrestaurant, lot, name, "
+ "place_ptr, place_ptr_id, provider, rating, serves_hot_dogs, serves_pizza"
+ )
+ with self.assertRaisesMessage(FieldError, msg):
Restaurant.objects.filter(supplier__name="foo")
def test_model_with_distinct_accessors(self):
@@ -65,7 +70,8 @@ class ModelInheritanceTests(TestCase):
# The Post model doesn't have an attribute called
# 'attached_%(class)s_set'.
- with self.assertRaises(AttributeError):
+ msg = "'Post' object has no attribute 'attached_%(class)s_set'"
+ with self.assertRaisesMessage(AttributeError, msg):
getattr(post, "attached_%(class)s_set")
def test_model_with_distinct_related_query_name(self):
diff --git a/tests/multiple_database/tests.py b/tests/multiple_database/tests.py
index 9edc58679a..8c4e8a8d8c 100644
--- a/tests/multiple_database/tests.py
+++ b/tests/multiple_database/tests.py
@@ -321,27 +321,39 @@ class QueryTestCase(TestCase):
mark = Person.objects.using('other').create(name="Mark Pilgrim")
# Set a foreign key set with an object from a different database
- with self.assertRaises(ValueError):
+ msg = (
+ 'Cannot assign "<Person: Marty Alchin>": the current database '
+ 'router prevents this relation.'
+ )
+ with self.assertRaisesMessage(ValueError, msg):
with transaction.atomic(using='default'):
marty.edited.set([pro, dive])
# Add to an m2m with an object from a different database
- with self.assertRaises(ValueError):
+ msg = (
+ 'Cannot add "<Book: Dive into Python>": instance is on '
+ 'database "default", value is on database "other"'
+ )
+ with self.assertRaisesMessage(ValueError, msg):
with transaction.atomic(using='default'):
marty.book_set.add(dive)
# Set a m2m with an object from a different database
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, msg):
with transaction.atomic(using='default'):
marty.book_set.set([pro, dive])
# Add to a reverse m2m with an object from a different database
- with self.assertRaises(ValueError):
+ msg = (
+ 'Cannot add "<Person: Marty Alchin>": instance is on '
+ 'database "other", value is on database "default"'
+ )
+ with self.assertRaisesMessage(ValueError, msg):
with transaction.atomic(using='other'):
dive.authors.add(marty)
# Set a reverse m2m with an object from a different database
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, msg):
with transaction.atomic(using='other'):
dive.authors.set([mark, marty])
@@ -537,16 +549,20 @@ class QueryTestCase(TestCase):
dive = Book.objects.using('other').create(title="Dive into Python", published=datetime.date(2009, 5, 4))
# Set a foreign key with an object from a different database
- with self.assertRaises(ValueError):
+ msg = (
+ 'Cannot assign "<Person: Marty Alchin>": the current database '
+ 'router prevents this relation.'
+ )
+ with self.assertRaisesMessage(ValueError, msg):
dive.editor = marty
# Set a foreign key set with an object from a different database
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, msg):
with transaction.atomic(using='default'):
marty.edited.set([pro, dive])
# Add to a foreign key set with an object from a different database
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, msg):
with transaction.atomic(using='default'):
marty.edited.add(dive)
@@ -655,7 +671,11 @@ class QueryTestCase(TestCase):
# Set a one-to-one relation with an object from a different database
alice_profile = UserProfile.objects.using('default').create(user=alice, flavor='chocolate')
- with self.assertRaises(ValueError):
+ msg = (
+ 'Cannot assign "<UserProfile: UserProfile object (1)>": the '
+ 'current database router prevents this relation.'
+ )
+ with self.assertRaisesMessage(ValueError, msg):
bob.userprofile = alice_profile
# BUT! if you assign a FK object when the base object hasn't
@@ -810,11 +830,19 @@ class QueryTestCase(TestCase):
Review.objects.using('other').create(source="Python Weekly", content_object=dive)
# Set a foreign key with an object from a different database
- with self.assertRaises(ValueError):
+ msg = (
+ 'Cannot assign "<ContentType: book>": the current database router '
+ 'prevents this relation.'
+ )
+ with self.assertRaisesMessage(ValueError, msg):
review1.content_object = dive
# Add to a foreign key set with an object from a different database
- with self.assertRaises(ValueError):
+ msg = (
+ "<Review: Python Monthly> instance isn't saved. "
+ "Use bulk=False or save the object first."
+ )
+ with self.assertRaisesMessage(ValueError, msg):
with transaction.atomic(using='other'):
dive.reviews.add(review1)
@@ -913,11 +941,15 @@ class QueryTestCase(TestCase):
# When you call __str__ on the query object, it doesn't know about using
# so it falls back to the default. If the subquery explicitly uses a
# different database, an error should be raised.
- with self.assertRaises(ValueError):
+ msg = (
+ "Subqueries aren't allowed across different databases. Force the "
+ "inner query to be evaluated using `list(inner_query)`."
+ )
+ with self.assertRaisesMessage(ValueError, msg):
str(qs.query)
# Evaluating the query shouldn't work, either
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, msg):
for obj in qs:
pass
diff --git a/tests/null_queries/tests.py b/tests/null_queries/tests.py
index 221bd05946..342b43f126 100644
--- a/tests/null_queries/tests.py
+++ b/tests/null_queries/tests.py
@@ -32,11 +32,12 @@ class NullQueriesTests(TestCase):
self.assertSequenceEqual(Choice.objects.exclude(choice=None).order_by('id'), [c1, c2])
# Valid query, but fails because foo isn't a keyword
- with self.assertRaises(FieldError):
+ msg = "Cannot resolve keyword 'foo' into field. Choices are: choice, id, poll, poll_id"
+ with self.assertRaisesMessage(FieldError, msg):
Choice.objects.filter(foo__exact=None)
# Can't use None on anything other than __exact and __iexact
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, 'Cannot use None as a query value'):
Choice.objects.filter(id__gt=None)
# Related managers use __exact=None implicitly if the object hasn't been saved.
diff --git a/tests/one_to_one/tests.py b/tests/one_to_one/tests.py
index 67eed38a93..82a061b736 100644
--- a/tests/one_to_one/tests.py
+++ b/tests/one_to_one/tests.py
@@ -226,7 +226,11 @@ class OneToOneTests(TestCase):
setattr(p, 'restaurant', None)
# You also can't assign an object of the wrong type here
- with self.assertRaises(ValueError):
+ msg = (
+ 'Cannot assign "<Place: Demon Dogs the place>": '
+ '"Place.restaurant" must be a "Restaurant" instance.'
+ )
+ with self.assertRaisesMessage(ValueError, msg):
setattr(p, 'restaurant', p)
# Creation using keyword argument should cache the related object.
diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py
index 7be7cbbac4..85de08b184 100644
--- a/tests/prefetch_related/tests.py
+++ b/tests/prefetch_related/tests.py
@@ -199,14 +199,22 @@ class PrefetchRelatedTests(TestCase):
def test_attribute_error(self):
qs = Reader.objects.all().prefetch_related('books_read__xyz')
- with self.assertRaises(AttributeError) as cm:
+ msg = (
+ "Cannot find 'xyz' on Book object, 'books_read__xyz' "
+ "is an invalid parameter to prefetch_related()"
+ )
+ with self.assertRaisesMessage(AttributeError, msg) as cm:
list(qs)
self.assertIn('prefetch_related', str(cm.exception))
def test_invalid_final_lookup(self):
qs = Book.objects.prefetch_related('authors__name')
- with self.assertRaises(ValueError) as cm:
+ msg = (
+ "'authors__name' does not resolve to an item that supports "
+ "prefetching - this is an invalid parameter to prefetch_related()."
+ )
+ with self.assertRaisesMessage(ValueError, msg) as cm:
list(qs)
self.assertIn('prefetch_related', str(cm.exception))
@@ -337,14 +345,22 @@ class CustomPrefetchTests(TestCase):
def test_ambiguous(self):
# Ambiguous: Lookup was already seen with a different queryset.
- with self.assertRaises(ValueError):
+ msg = (
+ "'houses' lookup was already seen with a different queryset. You "
+ "may need to adjust the ordering of your lookups."
+ )
+ with self.assertRaisesMessage(ValueError, msg):
self.traverse_qs(
Person.objects.prefetch_related('houses__rooms', Prefetch('houses', queryset=House.objects.all())),
[['houses', 'rooms']]
)
# Ambiguous: Lookup houses_lst doesn't yet exist when performing houses_lst__rooms.
- with self.assertRaises(AttributeError):
+ msg = (
+ "Cannot find 'houses_lst' on Person object, 'houses_lst__rooms' is "
+ "an invalid parameter to prefetch_related()"
+ )
+ with self.assertRaisesMessage(AttributeError, msg):
self.traverse_qs(
Person.objects.prefetch_related(
'houses_lst__rooms',
diff --git a/tests/queries/tests.py b/tests/queries/tests.py
index 75425f86ab..47f2ece35b 100644
--- a/tests/queries/tests.py
+++ b/tests/queries/tests.py
@@ -2957,7 +2957,8 @@ class WhereNodeTest(TestCase):
class QuerySetExceptionTests(TestCase):
def test_iter_exceptions(self):
qs = ExtraInfo.objects.only('author')
- with self.assertRaises(AttributeError):
+ msg = "'ManyToOneRel' object has no attribute 'attname'"
+ with self.assertRaisesMessage(AttributeError, msg):
list(qs)
def test_invalid_qs_list(self):
@@ -3735,9 +3736,10 @@ class TestTicket24279(TestCase):
class TestInvalidValuesRelation(TestCase):
def test_invalid_values(self):
- with self.assertRaises(ValueError):
+ msg = "invalid literal for int() with base 10: 'abc'"
+ with self.assertRaisesMessage(ValueError, msg):
Annotation.objects.filter(tag='abc')
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, msg):
Annotation.objects.filter(tag__in=[123, 'abc'])
diff --git a/tests/redirects_tests/tests.py b/tests/redirects_tests/tests.py
index 5bce11d800..e7f5dfb97d 100644
--- a/tests/redirects_tests/tests.py
+++ b/tests/redirects_tests/tests.py
@@ -57,7 +57,11 @@ class RedirectTests(TestCase):
@modify_settings(INSTALLED_APPS={'remove': 'django.contrib.sites'})
def test_sites_not_installed(self):
- with self.assertRaises(ImproperlyConfigured):
+ msg = (
+ 'You cannot use RedirectFallbackMiddleware when '
+ 'django.contrib.sites is not installed.'
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
RedirectFallbackMiddleware()
diff --git a/tests/reverse_lookup/tests.py b/tests/reverse_lookup/tests.py
index 0e0093f38e..b73b23e932 100644
--- a/tests/reverse_lookup/tests.py
+++ b/tests/reverse_lookup/tests.py
@@ -46,5 +46,9 @@ class ReverseLookupTests(TestCase):
"""
If a related_name is given you can't use the field name instead
"""
- with self.assertRaises(FieldError):
+ msg = (
+ "Cannot resolve keyword 'choice' into field. Choices are: "
+ "creator, creator_id, id, poll_choice, question, related_choice"
+ )
+ with self.assertRaisesMessage(FieldError, msg):
Poll.objects.get(choice__name__exact="This is the answer")
diff --git a/tests/select_for_update/tests.py b/tests/select_for_update/tests.py
index 7228af6e8e..eaedd506de 100644
--- a/tests/select_for_update/tests.py
+++ b/tests/select_for_update/tests.py
@@ -246,7 +246,8 @@ class SelectForUpdateTests(TransactionTestCase):
A TransactionManagementError is raised
when a select_for_update query is executed outside of a transaction.
"""
- with self.assertRaises(transaction.TransactionManagementError):
+ msg = 'select_for_update cannot be used outside of a transaction.'
+ with self.assertRaisesMessage(transaction.TransactionManagementError, msg):
list(Person.objects.all().select_for_update())
@skipUnlessDBFeature('has_select_for_update')
@@ -257,7 +258,8 @@ class SelectForUpdateTests(TransactionTestCase):
only when the query is executed.
"""
people = Person.objects.all().select_for_update()
- with self.assertRaises(transaction.TransactionManagementError):
+ msg = 'select_for_update cannot be used outside of a transaction.'
+ with self.assertRaisesMessage(transaction.TransactionManagementError, msg):
list(people)
@skipUnlessDBFeature('supports_select_for_update_with_limit')
diff --git a/tests/select_related/tests.py b/tests/select_related/tests.py
index 04f762f657..c19984e267 100644
--- a/tests/select_related/tests.py
+++ b/tests/select_related/tests.py
@@ -137,10 +137,6 @@ class SelectRelatedTests(TestCase):
.order_by('id')[0:1].get().genus.family.order.name)
self.assertEqual(s, 'Diptera')
- def test_depth_fields_fails(self):
- with self.assertRaises(TypeError):
- Species.objects.select_related('genus__family__order', depth=4)
-
def test_none_clears_list(self):
queryset = Species.objects.select_related('genus').select_related(None)
self.assertIs(queryset.query.select_related, False)
diff --git a/tests/settings_tests/tests.py b/tests/settings_tests/tests.py
index 1ab08cbd14..5a618954ed 100644
--- a/tests/settings_tests/tests.py
+++ b/tests/settings_tests/tests.py
@@ -238,7 +238,7 @@ class SettingsTests(SimpleTestCase):
getattr(settings, 'TEST')
def test_settings_delete_wrapped(self):
- with self.assertRaises(TypeError):
+ with self.assertRaisesMessage(TypeError, "can't delete _wrapped."):
delattr(settings, '_wrapped')
def test_override_settings_delete(self):
diff --git a/tests/sitemaps_tests/test_http.py b/tests/sitemaps_tests/test_http.py
index 45b95d0958..b1797840b3 100644
--- a/tests/sitemaps_tests/test_http.py
+++ b/tests/sitemaps_tests/test_http.py
@@ -16,6 +16,10 @@ from .models import TestModel
class HTTPSitemapTests(SitemapTestsBase):
+ use_sitemap_err_msg = (
+ 'To use sitemaps, either enable the sites framework or pass a '
+ 'Site/RequestSite object in your view.'
+ )
def test_simple_sitemap_index(self):
"A simple sitemap index can be rendered"
@@ -207,7 +211,7 @@ class HTTPSitemapTests(SitemapTestsBase):
Sitemap.get_urls and no Site objects exist
"""
Site.objects.all().delete()
- with self.assertRaises(ImproperlyConfigured):
+ with self.assertRaisesMessage(ImproperlyConfigured, self.use_sitemap_err_msg):
Sitemap().get_urls()
@modify_settings(INSTALLED_APPS={'remove': 'django.contrib.sites'})
@@ -217,7 +221,7 @@ class HTTPSitemapTests(SitemapTestsBase):
Sitemap.get_urls if Site objects exists, but the sites framework is not
actually installed.
"""
- with self.assertRaises(ImproperlyConfigured):
+ with self.assertRaisesMessage(ImproperlyConfigured, self.use_sitemap_err_msg):
Sitemap().get_urls()
def test_sitemap_item(self):
diff --git a/tests/staticfiles_tests/test_finders.py b/tests/staticfiles_tests/test_finders.py
index 20d3060092..9d5707cc2d 100644
--- a/tests/staticfiles_tests/test_finders.py
+++ b/tests/staticfiles_tests/test_finders.py
@@ -105,5 +105,10 @@ class TestMiscFinder(SimpleTestCase):
@override_settings(MEDIA_ROOT='')
def test_location_empty(self):
- with self.assertRaises(ImproperlyConfigured):
+ msg = (
+ "The storage backend of the staticfiles finder "
+ "<class 'django.contrib.staticfiles.finders.DefaultStorageFinder'> "
+ "doesn't have a valid location."
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
finders.DefaultStorageFinder()
diff --git a/tests/syndication_tests/tests.py b/tests/syndication_tests/tests.py
index 28fe026414..e98ac354b0 100644
--- a/tests/syndication_tests/tests.py
+++ b/tests/syndication_tests/tests.py
@@ -452,7 +452,11 @@ class SyndicationFeedTest(FeedTestCase):
An ImproperlyConfigured is raised if no link could be found for the
item(s).
"""
- with self.assertRaises(ImproperlyConfigured):
+ msg = (
+ 'Give your Article class a get_absolute_url() method, or define '
+ 'an item_link() method in your Feed class.'
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
self.client.get('/syndication/articles/')
def test_template_feed(self):
diff --git a/tests/template_tests/syntax_tests/i18n/test_blocktrans.py b/tests/template_tests/syntax_tests/i18n/test_blocktrans.py
index d8b1e807af..425e748d53 100644
--- a/tests/template_tests/syntax_tests/i18n/test_blocktrans.py
+++ b/tests/template_tests/syntax_tests/i18n/test_blocktrans.py
@@ -332,11 +332,13 @@ class TranslationBlockTransTagTests(SimpleTestCase):
self.assertEqual(rendered, '2 andere Super-Ergebnisse')
# Misuses
- with self.assertRaises(TemplateSyntaxError):
+ msg = "Unknown argument for 'blocktrans' tag: %r."
+ with self.assertRaisesMessage(TemplateSyntaxError, msg % 'month="May"'):
Template('{% load i18n %}{% blocktrans context with month="May" %}{{ month }}{% endblocktrans %}')
- with self.assertRaises(TemplateSyntaxError):
+ msg = '"context" in %r tag expected exactly one argument.' % 'blocktrans'
+ with self.assertRaisesMessage(TemplateSyntaxError, msg):
Template('{% load i18n %}{% blocktrans context %}{% endblocktrans %}')
- with self.assertRaises(TemplateSyntaxError):
+ with self.assertRaisesMessage(TemplateSyntaxError, msg):
Template(
'{% load i18n %}{% blocktrans count number=2 context %}'
'{{ number }} super result{% plural %}{{ number }}'
diff --git a/tests/template_tests/syntax_tests/test_filter_syntax.py b/tests/template_tests/syntax_tests/test_filter_syntax.py
index 738b3ed978..176475c04c 100644
--- a/tests/template_tests/syntax_tests/test_filter_syntax.py
+++ b/tests/template_tests/syntax_tests/test_filter_syntax.py
@@ -43,7 +43,8 @@ class FilterSyntaxTests(SimpleTestCase):
"""
Raise TemplateSyntaxError for a nonexistent filter
"""
- with self.assertRaises(TemplateSyntaxError):
+ msg = "Invalid filter: 'does_not_exist'"
+ with self.assertRaisesMessage(TemplateSyntaxError, msg):
self.engine.get_template('filter-syntax05')
@setup({'filter-syntax06': '{{ var|fil(ter) }}'})
@@ -52,7 +53,7 @@ class FilterSyntaxTests(SimpleTestCase):
Raise TemplateSyntaxError when trying to access a filter containing
an illegal character
"""
- with self.assertRaises(TemplateSyntaxError):
+ with self.assertRaisesMessage(TemplateSyntaxError, "Invalid filter: 'fil'"):
self.engine.get_template('filter-syntax06')
@setup({'filter-syntax07': "{% nothing_to_see_here %}"})
@@ -60,7 +61,11 @@ class FilterSyntaxTests(SimpleTestCase):
"""
Raise TemplateSyntaxError for invalid block tags
"""
- with self.assertRaises(TemplateSyntaxError):
+ msg = (
+ "Invalid block tag on line 1: 'nothing_to_see_here'. Did you "
+ "forget to register or load this tag?"
+ )
+ with self.assertRaisesMessage(TemplateSyntaxError, msg):
self.engine.get_template('filter-syntax07')
@setup({'filter-syntax08': "{% %}"})
diff --git a/tests/template_tests/syntax_tests/test_with.py b/tests/template_tests/syntax_tests/test_with.py
index c1d501c94d..d8f24349f5 100644
--- a/tests/template_tests/syntax_tests/test_with.py
+++ b/tests/template_tests/syntax_tests/test_with.py
@@ -6,6 +6,7 @@ from ..utils import setup
class WithTagTests(SimpleTestCase):
+ at_least_with_one_msg = "'with' expected at least one variable assignment"
@setup({'with01': '{% with key=dict.key %}{{ key }}{% endwith %}'})
def test_with01(self):
@@ -44,12 +45,12 @@ class WithTagTests(SimpleTestCase):
@setup({'with-error01': '{% with dict.key xx key %}{{ key }}{% endwith %}'})
def test_with_error01(self):
- with self.assertRaises(TemplateSyntaxError):
+ with self.assertRaisesMessage(TemplateSyntaxError, self.at_least_with_one_msg):
self.engine.render_to_string('with-error01', {'dict': {'key': 50}})
@setup({'with-error02': '{% with dict.key as %}{{ key }}{% endwith %}'})
def test_with_error02(self):
- with self.assertRaises(TemplateSyntaxError):
+ with self.assertRaisesMessage(TemplateSyntaxError, self.at_least_with_one_msg):
self.engine.render_to_string('with-error02', {'dict': {'key': 50}})
diff --git a/tests/template_tests/test_parser.py b/tests/template_tests/test_parser.py
index cd2f2ddc05..3dc731e0a9 100644
--- a/tests/template_tests/test_parser.py
+++ b/tests/template_tests/test_parser.py
@@ -40,7 +40,8 @@ class ParserTests(SimpleTestCase):
# Filtered variables should reject access of attributes beginning with
# underscores.
- with self.assertRaises(TemplateSyntaxError):
+ msg = "Variables and attributes may not begin with underscores: 'article._hidden'"
+ with self.assertRaisesMessage(TemplateSyntaxError, msg):
FilterExpression("article._hidden|upper", p)
def test_variable_parsing(self):
@@ -64,7 +65,8 @@ class ParserTests(SimpleTestCase):
# Variables should reject access of attributes beginning with
# underscores.
- with self.assertRaises(TemplateSyntaxError):
+ msg = "Variables and attributes may not begin with underscores: 'article._hidden'"
+ with self.assertRaisesMessage(TemplateSyntaxError, msg):
Variable("article._hidden")
# Variables should raise on non string type
diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py
index 06e2ce417c..80ee5a27b5 100644
--- a/tests/test_utils/tests.py
+++ b/tests/test_utils/tests.py
@@ -212,7 +212,8 @@ class AssertQuerysetEqualTests(TestCase):
def test_undefined_order(self):
# Using an unordered queryset with more than one ordered value
# is an error.
- with self.assertRaises(ValueError):
+ msg = 'Trying to compare non-ordered queryset against more than one ordered values'
+ with self.assertRaisesMessage(ValueError, msg):
self.assertQuerysetEqual(
Person.objects.all(),
[repr(self.p1), repr(self.p2)]
@@ -415,23 +416,29 @@ class AssertTemplateUsedContextManagerTests(SimpleTestCase):
self.assertTemplateUsed(response, 'template_used/base.html')
def test_failure(self):
- with self.assertRaises(TypeError):
+ msg = 'response and/or template_name argument must be provided'
+ with self.assertRaisesMessage(TypeError, msg):
with self.assertTemplateUsed():
pass
- with self.assertRaises(AssertionError):
+ msg = 'No templates used to render the response'
+ with self.assertRaisesMessage(AssertionError, msg):
with self.assertTemplateUsed(''):
pass
- with self.assertRaises(AssertionError):
+ with self.assertRaisesMessage(AssertionError, msg):
with self.assertTemplateUsed(''):
render_to_string('template_used/base.html')
- with self.assertRaises(AssertionError):
+ with self.assertRaisesMessage(AssertionError, msg):
with self.assertTemplateUsed(template_name=''):
pass
- with self.assertRaises(AssertionError):
+ msg = (
+ 'template_used/base.html was not rendered. Following '
+ 'templates were rendered: template_used/alternative.html'
+ )
+ with self.assertRaisesMessage(AssertionError, msg):
with self.assertTemplateUsed('template_used/base.html'):
render_to_string('template_used/alternative.html')
diff --git a/tests/timezones/tests.py b/tests/timezones/tests.py
index 7c83ffbc47..926b8de704 100644
--- a/tests/timezones/tests.py
+++ b/tests/timezones/tests.py
@@ -123,7 +123,8 @@ class LegacyDatabaseTests(TestCase):
@skipIfDBFeature('supports_timezones')
def test_aware_datetime_unsupported(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)
- with self.assertRaises(ValueError):
+ msg = 'backend does not support timezone-aware datetimes when USE_TZ is False.'
+ with self.assertRaisesMessage(ValueError, msg):
Event.objects.create(dt=dt)
def test_auto_now_and_auto_now_add(self):
@@ -647,7 +648,11 @@ class UnsupportedTimeZoneDatabaseTests(TestCase):
connections.databases['tz']['TIME_ZONE'] = 'Asia/Bangkok'
tz_conn = connections['tz']
try:
- with self.assertRaises(ImproperlyConfigured):
+ msg = (
+ "Connection 'tz' cannot set TIME_ZONE because its engine "
+ "handles time zones conversions natively."
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
tz_conn.cursor()
finally:
connections['tz'].close() # in case the test fails
@@ -1033,7 +1038,8 @@ class TemplateTests(SimpleTestCase):
self.assertEqual(tpl.render(Context()), "Europe/Paris")
def test_get_current_timezone_templatetag_invalid_argument(self):
- with self.assertRaises(TemplateSyntaxError):
+ msg = "'get_current_timezone' requires 'as variable' (got ['get_current_timezone'])"
+ with self.assertRaisesMessage(TemplateSyntaxError, msg):
Template("{% load tz %}{% get_current_timezone %}").render()
@skipIf(sys.platform.startswith('win'), "Windows uses non-standard time zone names")
diff --git a/tests/transaction_hooks/tests.py b/tests/transaction_hooks/tests.py
index 049211139d..ed3cf18be2 100644
--- a/tests/transaction_hooks/tests.py
+++ b/tests/transaction_hooks/tests.py
@@ -214,7 +214,8 @@ class TestConnectionOnCommit(TransactionTestCase):
try:
connection.set_autocommit(False)
- with self.assertRaises(transaction.TransactionManagementError):
+ msg = 'on_commit() cannot be used in manual transaction management'
+ with self.assertRaisesMessage(transaction.TransactionManagementError, msg):
transaction.on_commit(should_never_be_called)
finally:
connection.set_autocommit(True)
diff --git a/tests/transactions/tests.py b/tests/transactions/tests.py
index 398a14be4e..7d4d4b777a 100644
--- a/tests/transactions/tests.py
+++ b/tests/transactions/tests.py
@@ -299,20 +299,21 @@ class AtomicMergeTests(TransactionTestCase):
class AtomicErrorsTests(TransactionTestCase):
available_apps = ['transactions']
+ forbidden_atomic_msg = "This is forbidden when an 'atomic' block is active."
def test_atomic_prevents_setting_autocommit(self):
autocommit = transaction.get_autocommit()
with transaction.atomic():
- with self.assertRaises(transaction.TransactionManagementError):
+ with self.assertRaisesMessage(transaction.TransactionManagementError, self.forbidden_atomic_msg):
transaction.set_autocommit(not autocommit)
# Make sure autocommit wasn't changed.
self.assertEqual(connection.autocommit, autocommit)
def test_atomic_prevents_calling_transaction_methods(self):
with transaction.atomic():
- with self.assertRaises(transaction.TransactionManagementError):
+ with self.assertRaisesMessage(transaction.TransactionManagementError, self.forbidden_atomic_msg):
transaction.commit()
- with self.assertRaises(transaction.TransactionManagementError):
+ with self.assertRaisesMessage(transaction.TransactionManagementError, self.forbidden_atomic_msg):
transaction.rollback()
def test_atomic_prevents_queries_in_broken_transaction(self):
@@ -322,7 +323,11 @@ class AtomicErrorsTests(TransactionTestCase):
with self.assertRaises(IntegrityError):
r2.save(force_insert=True)
# The transaction is marked as needing rollback.
- with self.assertRaises(transaction.TransactionManagementError):
+ msg = (
+ "An error occurred in the current transaction. You can't "
+ "execute queries until the end of the 'atomic' block."
+ )
+ with self.assertRaisesMessage(transaction.TransactionManagementError, msg):
r2.save(force_update=True)
self.assertEqual(Reporter.objects.get(pk=r1.pk).last_name, "Haddock")
diff --git a/tests/update/tests.py b/tests/update/tests.py
index ba7ffd5c88..923af40305 100644
--- a/tests/update/tests.py
+++ b/tests/update/tests.py
@@ -123,7 +123,8 @@ class AdvancedTests(TestCase):
We do not support update on already sliced query sets.
"""
method = DataPoint.objects.all()[:2].update
- with self.assertRaises(AssertionError):
+ msg = 'Cannot update a query once a slice has been taken.'
+ with self.assertRaisesMessage(AssertionError, msg):
method(another_value='another thing')
def test_update_respects_to_field(self):
diff --git a/tests/update_only_fields/tests.py b/tests/update_only_fields/tests.py
index 743b5fda8d..58ae94b7cc 100644
--- a/tests/update_only_fields/tests.py
+++ b/tests/update_only_fields/tests.py
@@ -5,6 +5,8 @@ from .models import Account, Employee, Person, Profile, ProxyEmployee
class UpdateOnlyFieldsTests(TestCase):
+ msg = 'The following fields do not exist in this model or are m2m fields: %s'
+
def test_update_fields_basic(self):
s = Person.objects.create(name='Sara', gender='F')
self.assertEqual(s.gender, 'F')
@@ -120,7 +122,7 @@ class UpdateOnlyFieldsTests(TestCase):
a2 = Account.objects.create(num=2)
e1.accounts.set([a1, a2])
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, self.msg % 'accounts'):
e1.save(update_fields=['accounts'])
def test_update_fields_inheritance(self):
@@ -201,10 +203,12 @@ class UpdateOnlyFieldsTests(TestCase):
def test_update_fields_incorrect_params(self):
s = Person.objects.create(name='Sara', gender='F')
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, self.msg % 'first_name'):
s.save(update_fields=['first_name'])
- with self.assertRaises(ValueError):
+ # "name" is treated as an iterable so the output is something like
+ # "n, a, m, e" but the order isn't deterministic.
+ with self.assertRaisesMessage(ValueError, self.msg % ''):
s.save(update_fields="name")
def test_empty_update_fields(self):
diff --git a/tests/urlpatterns_reverse/tests.py b/tests/urlpatterns_reverse/tests.py
index ff204c5650..7f565fe487 100644
--- a/tests/urlpatterns_reverse/tests.py
+++ b/tests/urlpatterns_reverse/tests.py
@@ -1067,7 +1067,12 @@ class NoRootUrlConfTests(SimpleTestCase):
"""Tests for handler404 and handler500 if ROOT_URLCONF is None"""
def test_no_handler_exception(self):
- with self.assertRaises(ImproperlyConfigured):
+ msg = (
+ "The included URLconf 'None' does not appear to have any patterns "
+ "in it. If you see valid patterns in the file then the issue is "
+ "probably caused by a circular import."
+ )
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
self.client.get('/test/me/')
diff --git a/tests/user_commands/tests.py b/tests/user_commands/tests.py
index 19ae51b096..3900a58247 100644
--- a/tests/user_commands/tests.py
+++ b/tests/user_commands/tests.py
@@ -46,7 +46,7 @@ class CommandTests(SimpleTestCase):
def test_explode(self):
""" An unknown command raises CommandError """
- with self.assertRaises(CommandError):
+ with self.assertRaisesMessage(CommandError, "Unknown command: 'explode'"):
management.call_command(('explode',))
def test_system_exit(self):
@@ -215,5 +215,6 @@ class CommandRunTests(AdminScriptTestCase):
class UtilsTests(SimpleTestCase):
def test_no_existent_external_program(self):
- with self.assertRaises(CommandError):
+ msg = 'Error executing a_42_command_that_doesnt_exist_42'
+ with self.assertRaisesMessage(CommandError, msg):
popen_wrapper(['a_42_command_that_doesnt_exist_42'])
diff --git a/tests/validators/tests.py b/tests/validators/tests.py
index 8620e7dc35..bc8ee7fb1d 100644
--- a/tests/validators/tests.py
+++ b/tests/validators/tests.py
@@ -334,7 +334,8 @@ class TestSimpleValidators(SimpleTestCase):
self.assertEqual(repr(v), "ValidationError({'first': ['First Problem']})")
def test_regex_validator_flags(self):
- with self.assertRaises(TypeError):
+ msg = 'If the flags are set, regex must be a regular expression string.'
+ with self.assertRaisesMessage(TypeError, msg):
RegexValidator(re.compile('a'), flags=re.IGNORECASE)
def test_max_length_validator_message(self):