summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMorgan Aubert <morgan.aubert@impakfinance.com>2018-04-27 17:18:15 -0400
committerTim Graham <timograham@gmail.com>2018-05-09 11:40:28 -0400
commit704443acacf0dfbcb1c52df4b260585055754ce7 (patch)
tree600147bf6114d7b490fcd253ff9797b7e7531c09
parent7ba040de7703fd06b9b35ddd31da40103d911c30 (diff)
Fixed #29363 -- Added SimpleTestCase.assertWarnsMessage().
-rw-r--r--django/test/testcases.py43
-rw-r--r--docs/internals/contributing/writing-code/coding-style.txt12
-rw-r--r--docs/releases/2.1.txt3
-rw-r--r--docs/topics/testing/tools.txt11
-rw-r--r--tests/admin_views/test_static_deprecation.py8
-rw-r--r--tests/backends/postgresql/tests.py14
-rw-r--r--tests/backends/tests.py9
-rw-r--r--tests/cache/tests.py7
-rw-r--r--tests/deprecation/tests.py153
-rw-r--r--tests/fixtures/tests.py11
-rw-r--r--tests/fixtures_regress/tests.py38
-rw-r--r--tests/forms_tests/tests/test_media.py10
-rw-r--r--tests/from_db_value/test_deprecated.py17
-rw-r--r--tests/get_earliest_or_latest/tests.py14
-rw-r--r--tests/migrations/test_graph.py14
-rw-r--r--tests/modeladmin/test_has_add_permission_obj_deprecation.py13
-rw-r--r--tests/pagination/tests.py26
-rw-r--r--tests/settings_tests/tests.py11
-rw-r--r--tests/staticfiles_tests/test_templatetag_deprecation.py13
-rw-r--r--tests/test_utils/tests.py25
-rw-r--r--tests/timezones/tests.py35
21 files changed, 206 insertions, 281 deletions
diff --git a/django/test/testcases.py b/django/test/testcases.py
index 8a85aa2a9f..1fac9ef931 100644
--- a/django/test/testcases.py
+++ b/django/test/testcases.py
@@ -585,10 +585,23 @@ class SimpleTestCase(unittest.TestCase):
)
@contextmanager
- def _assert_raises_message_cm(self, expected_exception, expected_message):
- with self.assertRaises(expected_exception) as cm:
+ def _assert_raises_or_warns_cm(self, func, cm_attr, expected_exception, expected_message):
+ with func(expected_exception) as cm:
yield cm
- self.assertIn(expected_message, str(cm.exception))
+ self.assertIn(expected_message, str(getattr(cm, cm_attr)))
+
+ def _assertFooMessage(self, func, cm_attr, expected_exception, expected_message, *args, **kwargs):
+ callable_obj = None
+ if args:
+ callable_obj = args[0]
+ args = args[1:]
+ cm = self._assert_raises_or_warns_cm(func, cm_attr, expected_exception, expected_message)
+ # Assertion used in context manager fashion.
+ if callable_obj is None:
+ return cm
+ # Assertion was passed a callable.
+ with cm:
+ callable_obj(*args, **kwargs)
def assertRaisesMessage(self, expected_exception, expected_message, *args, **kwargs):
"""
@@ -601,18 +614,20 @@ class SimpleTestCase(unittest.TestCase):
args: Function to be called and extra positional args.
kwargs: Extra kwargs.
"""
- callable_obj = None
- if args:
- callable_obj = args[0]
- args = args[1:]
+ return self._assertFooMessage(
+ self.assertRaises, 'exception', expected_exception, expected_message,
+ *args, **kwargs
+ )
- cm = self._assert_raises_message_cm(expected_exception, expected_message)
- # Assertion used in context manager fashion.
- if callable_obj is None:
- return cm
- # Assertion was passed a callable.
- with cm:
- callable_obj(*args, **kwargs)
+ def assertWarnsMessage(self, expected_warning, expected_message, *args, **kwargs):
+ """
+ Same as assertRaisesMessage but for assertWarns() instead of
+ assertRaises().
+ """
+ return self._assertFooMessage(
+ self.assertWarns, 'warning', expected_warning, expected_message,
+ *args, **kwargs
+ )
def assertFieldOutput(self, fieldclass, valid, invalid, field_args=None,
field_kwargs=None, empty_value=''):
diff --git a/docs/internals/contributing/writing-code/coding-style.txt b/docs/internals/contributing/writing-code/coding-style.txt
index 5721c969cf..b34be61bc4 100644
--- a/docs/internals/contributing/writing-code/coding-style.txt
+++ b/docs/internals/contributing/writing-code/coding-style.txt
@@ -62,10 +62,14 @@ Python style
* In docstrings, follow the style of existing docstrings and :pep:`257`.
-* In tests, use :meth:`~django.test.SimpleTestCase.assertRaisesMessage` instead
- of :meth:`~unittest.TestCase.assertRaises` so you can check the exception
- message. Use :meth:`~unittest.TestCase.assertRaisesRegex` only if you need
- regular expression matching.
+* In tests, use
+ :meth:`~django.test.SimpleTestCase.assertRaisesMessage` and
+ :meth:`~django.test.SimpleTestCase.assertWarnsMessage`
+ instead of :meth:`~unittest.TestCase.assertRaises` and
+ :meth:`~unittest.TestCase.assertWarns` so you can check the
+ exception or warning message. Use :meth:`~unittest.TestCase.assertRaisesRegex`
+ and :meth:`~unittest.TestCase.assertWarnsRegex` only if you need regular
+ expression matching.
* In test docstrings, state the expected behavior that each test demonstrates.
Don't include preambles such as "Tests that" or "Ensures that".
diff --git a/docs/releases/2.1.txt b/docs/releases/2.1.txt
index e6b8b29a64..3152a42d76 100644
--- a/docs/releases/2.1.txt
+++ b/docs/releases/2.1.txt
@@ -277,6 +277,9 @@ Tests
dictionary as JSON if ``content_type='application/json'``. You can customize
the JSON encoder with test client's ``json_encoder`` parameter.
+* The new :meth:`.SimpleTestCase.assertWarnsMessage` method is a simpler
+ version of :meth:`~unittest.TestCase.assertWarnsRegex`.
+
URLs
~~~~
diff --git a/docs/topics/testing/tools.txt b/docs/topics/testing/tools.txt
index ef818f1bb8..6e83bbc6a9 100644
--- a/docs/topics/testing/tools.txt
+++ b/docs/topics/testing/tools.txt
@@ -692,6 +692,8 @@ A subclass of :class:`unittest.TestCase` that adds this functionality:
* Checking that a callable :meth:`raises a certain exception
<SimpleTestCase.assertRaisesMessage>`.
+ * Checking that a callable :meth:`triggers a certain warning
+ <SimpleTestCase.assertWarnsMessage>`.
* Testing form field :meth:`rendering and error treatment
<SimpleTestCase.assertFieldOutput>`.
* Testing :meth:`HTML responses for the presence/lack of a given fragment
@@ -1362,6 +1364,15 @@ your test suite.
with self.assertRaisesMessage(ValueError, 'invalid literal for int()'):
int('a')
+.. method:: SimpleTestCase.assertWarnsMessage(expected_warning, expected_message, callable, *args, **kwargs)
+ SimpleTestCase.assertWarnsMessage(expected_warning, expected_message)
+
+ .. versionadded:: 2.1
+
+ Analogous to :meth:`SimpleTestCase.assertRaisesMessage` but for
+ :meth:`~unittest.TestCase.assertWarnsRegex` instead of
+ :meth:`~unittest.TestCase.assertRaisesRegex`.
+
.. method:: SimpleTestCase.assertFieldOutput(fieldclass, valid, invalid, field_args=None, field_kwargs=None, empty_value='')
Asserts that a form field behaves correctly with various inputs.
diff --git a/tests/admin_views/test_static_deprecation.py b/tests/admin_views/test_static_deprecation.py
index fb64df6f5f..166e27ef37 100644
--- a/tests/admin_views/test_static_deprecation.py
+++ b/tests/admin_views/test_static_deprecation.py
@@ -1,5 +1,3 @@
-import warnings
-
from django.contrib.admin.templatetags.admin_static import static
from django.contrib.staticfiles.storage import staticfiles_storage
from django.test import SimpleTestCase
@@ -19,12 +17,8 @@ class AdminStaticDeprecationTests(SimpleTestCase):
old_url = staticfiles_storage.base_url
staticfiles_storage.base_url = '/test/'
try:
- with warnings.catch_warnings(record=True) as recorded:
- warnings.simplefilter('always')
+ with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
url = static('path')
self.assertEqual(url, '/test/path')
- self.assertEqual(len(recorded), 1)
- self.assertIs(recorded[0].category, RemovedInDjango30Warning)
- self.assertEqual(str(recorded[0].message), msg)
finally:
staticfiles_storage.base_url = old_url
diff --git a/tests/backends/postgresql/tests.py b/tests/backends/postgresql/tests.py
index 33047df83b..e64e097fd1 100644
--- a/tests/backends/postgresql/tests.py
+++ b/tests/backends/postgresql/tests.py
@@ -1,5 +1,4 @@
import unittest
-import warnings
from unittest import mock
from django.core.exceptions import ImproperlyConfigured
@@ -24,7 +23,14 @@ class Tests(TestCase):
self.assertIsNone(nodb_conn.settings_dict['NAME'])
# Now assume the 'postgres' db isn't available
- with warnings.catch_warnings(record=True) as w:
+ msg = (
+ "Normally Django will use a connection to the 'postgres' database "
+ "to avoid running initialization queries against the production "
+ "database when it's not needed (for example, when running tests). "
+ "Django was unable to create a connection to the 'postgres' "
+ "database and will use the first PostgreSQL database instead."
+ )
+ with self.assertWarnsMessage(RuntimeWarning, msg):
with mock.patch('django.db.backends.base.base.BaseDatabaseWrapper.connect',
side_effect=mocked_connect, autospec=True):
with mock.patch.object(
@@ -32,13 +38,9 @@ class Tests(TestCase):
'settings_dict',
{**connection.settings_dict, 'NAME': 'postgres'},
):
- warnings.simplefilter('always', RuntimeWarning)
nodb_conn = connection._nodb_connection
self.assertIsNotNone(nodb_conn.settings_dict['NAME'])
self.assertEqual(nodb_conn.settings_dict['NAME'], connections['other'].settings_dict['NAME'])
- # Check a RuntimeWarning has been emitted
- self.assertEqual(len(w), 1)
- self.assertEqual(w[0].message.__class__, RuntimeWarning)
def test_database_name_too_long(self):
from django.db.backends.postgresql.base import DatabaseWrapper
diff --git a/tests/backends/tests.py b/tests/backends/tests.py
index 32d76577a1..6e6868edfb 100644
--- a/tests/backends/tests.py
+++ b/tests/backends/tests.py
@@ -441,13 +441,10 @@ class BackendTestCase(TransactionTestCase):
cursor.execute("SELECT 3" + new_connection.features.bare_select_suffix)
cursor.execute("SELECT 4" + new_connection.features.bare_select_suffix)
- with warnings.catch_warnings(record=True) as w:
+ msg = "Limit for query logging exceeded, only the last 3 queries will be returned."
+ with self.assertWarnsMessage(UserWarning, msg):
self.assertEqual(3, len(new_connection.queries))
- self.assertEqual(1, len(w))
- self.assertEqual(
- str(w[0].message),
- "Limit for query logging exceeded, only the last 3 queries will be returned."
- )
+
finally:
BaseDatabaseWrapper.queries_limit = old_queries_limit
new_connection.close()
diff --git a/tests/cache/tests.py b/tests/cache/tests.py
index 890f8b6a9e..9dd7fa78e0 100644
--- a/tests/cache/tests.py
+++ b/tests/cache/tests.py
@@ -10,7 +10,6 @@ import tempfile
import threading
import time
import unittest
-import warnings
from unittest import mock
from django.conf import settings
@@ -632,12 +631,8 @@ class BaseCacheTests:
cache.key_func = func
try:
- with warnings.catch_warnings(record=True) as w:
- warnings.simplefilter("always")
+ with self.assertWarnsMessage(CacheKeyWarning, expected_warning):
cache.set(key, 'value')
- self.assertEqual(len(w), 1)
- self.assertIsInstance(w[0].message, CacheKeyWarning)
- self.assertEqual(str(w[0].message.args[0]), expected_warning)
finally:
cache.key_func = old_func
diff --git a/tests/deprecation/tests.py b/tests/deprecation/tests.py
index ef0284b378..b3ab78d1ca 100644
--- a/tests/deprecation/tests.py
+++ b/tests/deprecation/tests.py
@@ -23,107 +23,94 @@ class RenameMethodsTests(SimpleTestCase):
Ensure a warning is raised upon class definition to suggest renaming
the faulty method.
"""
- with warnings.catch_warnings(record=True) as recorded:
- warnings.simplefilter('always')
-
+ msg = '`Manager.old` method should be renamed `new`.'
+ with self.assertWarnsMessage(DeprecationWarning, msg):
class Manager(metaclass=RenameManagerMethods):
def old(self):
pass
- self.assertEqual(len(recorded), 1)
- msg = str(recorded[0].message)
- self.assertEqual(msg, '`Manager.old` method should be renamed `new`.')
def test_get_new_defined(self):
"""
Ensure `old` complains and not `new` when only `new` is defined.
"""
- with warnings.catch_warnings(record=True) as recorded:
- warnings.simplefilter('ignore')
+ class Manager(metaclass=RenameManagerMethods):
+ def new(self):
+ pass
+ manager = Manager()
- class Manager(metaclass=RenameManagerMethods):
- def new(self):
- pass
+ with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
- manager = Manager()
manager.new()
- self.assertEqual(len(recorded), 0)
+ self.assertEqual(len(recorded), 0)
+
+ msg = '`Manager.old` is deprecated, use `new` instead.'
+ with self.assertWarnsMessage(DeprecationWarning, msg):
manager.old()
- self.assertEqual(len(recorded), 1)
- msg = str(recorded.pop().message)
- self.assertEqual(msg, '`Manager.old` is deprecated, use `new` instead.')
def test_get_old_defined(self):
"""
Ensure `old` complains when only `old` is defined.
"""
- with warnings.catch_warnings(record=True) as recorded:
- warnings.simplefilter('ignore')
+ class Manager(metaclass=RenameManagerMethods):
+ def old(self):
+ pass
+ manager = Manager()
- class Manager(metaclass=RenameManagerMethods):
- def old(self):
- pass
+ with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
- manager = Manager()
manager.new()
- self.assertEqual(len(recorded), 0)
+ self.assertEqual(len(recorded), 0)
+
+ msg = '`Manager.old` is deprecated, use `new` instead.'
+ with self.assertWarnsMessage(DeprecationWarning, msg):
manager.old()
- self.assertEqual(len(recorded), 1)
- msg = str(recorded.pop().message)
- self.assertEqual(msg, '`Manager.old` is deprecated, use `new` instead.')
def test_deprecated_subclass_renamed(self):
"""
Ensure the correct warnings are raised when a class that didn't rename
`old` subclass one that did.
"""
- with warnings.catch_warnings(record=True) as recorded:
- warnings.simplefilter('ignore')
+ class Renamed(metaclass=RenameManagerMethods):
+ def new(self):
+ pass
- class Renamed(metaclass=RenameManagerMethods):
- def new(self):
- pass
+ class Deprecated(Renamed):
+ def old(self):
+ super().old()
- class Deprecated(Renamed):
- def old(self):
- super().old()
- warnings.simplefilter('always')
- deprecated = Deprecated()
+ deprecated = Deprecated()
+
+ msg = '`Renamed.old` is deprecated, use `new` instead.'
+ with self.assertWarnsMessage(DeprecationWarning, msg):
deprecated.new()
- self.assertEqual(len(recorded), 1)
- msg = str(recorded.pop().message)
- self.assertEqual(msg, '`Renamed.old` is deprecated, use `new` instead.')
- recorded[:] = []
+
+ msg = '`Deprecated.old` is deprecated, use `new` instead.'
+ with self.assertWarnsMessage(DeprecationWarning, msg):
deprecated.old()
- self.assertEqual(len(recorded), 2)
- msgs = [str(warning.message) for warning in recorded]
- self.assertEqual(msgs, [
- '`Deprecated.old` is deprecated, use `new` instead.',
- '`Renamed.old` is deprecated, use `new` instead.',
- ])
def test_renamed_subclass_deprecated(self):
"""
Ensure the correct warnings are raised when a class that renamed
`old` subclass one that didn't.
"""
- with warnings.catch_warnings(record=True) as recorded:
- warnings.simplefilter('ignore')
+ class Deprecated(metaclass=RenameManagerMethods):
+ def old(self):
+ pass
- class Deprecated(metaclass=RenameManagerMethods):
- def old(self):
- pass
+ class Renamed(Deprecated):
+ def new(self):
+ super().new()
- class Renamed(Deprecated):
- def new(self):
- super().new()
+ renamed = Renamed()
+
+ with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
- renamed = Renamed()
renamed.new()
- self.assertEqual(len(recorded), 0)
+ self.assertEqual(len(recorded), 0)
+
+ msg = '`Renamed.old` is deprecated, use `new` instead.'
+ with self.assertWarnsMessage(DeprecationWarning, msg):
renamed.old()
- self.assertEqual(len(recorded), 1)
- msg = str(recorded.pop().message)
- self.assertEqual(msg, '`Renamed.old` is deprecated, use `new` instead.')
def test_deprecated_subclass_renamed_and_mixins(self):
"""
@@ -131,36 +118,30 @@ class RenameMethodsTests(SimpleTestCase):
class that renamed `old` and mixins that may or may not have renamed
`new`.
"""
- with warnings.catch_warnings(record=True) as recorded:
- warnings.simplefilter('ignore')
+ class Renamed(metaclass=RenameManagerMethods):
+ def new(self):
+ pass
- class Renamed(metaclass=RenameManagerMethods):
- def new(self):
- pass
+ class RenamedMixin:
+ def new(self):
+ super().new()
- class RenamedMixin:
- def new(self):
- super().new()
+ class DeprecatedMixin:
+ def old(self):
+ super().old()
- class DeprecatedMixin:
- def old(self):
- super().old()
+ class Deprecated(DeprecatedMixin, RenamedMixin, Renamed):
+ pass
- class Deprecated(DeprecatedMixin, RenamedMixin, Renamed):
- pass
- warnings.simplefilter('always')
- deprecated = Deprecated()
+ deprecated = Deprecated()
+
+ msg = '`RenamedMixin.old` is deprecated, use `new` instead.'
+ with self.assertWarnsMessage(DeprecationWarning, msg):
deprecated.new()
- self.assertEqual(len(recorded), 1)
- msg = str(recorded.pop().message)
- self.assertEqual(msg, '`RenamedMixin.old` is deprecated, use `new` instead.')
+
+ msg = '`DeprecatedMixin.old` is deprecated, use `new` instead.'
+ with self.assertWarnsMessage(DeprecationWarning, msg):
deprecated.old()
- self.assertEqual(len(recorded), 2)
- msgs = [str(warning.message) for warning in recorded]
- self.assertEqual(msgs, [
- '`DeprecatedMixin.old` is deprecated, use `new` instead.',
- '`RenamedMixin.old` is deprecated, use `new` instead.',
- ])
class DeprecationInstanceCheckTest(SimpleTestCase):
@@ -170,7 +151,5 @@ class DeprecationInstanceCheckTest(SimpleTestCase):
deprecation_warning = RemovedInNextVersionWarning
msg = '`Manager` is deprecated, use `fake.path.Foo` instead.'
- with warnings.catch_warnings():
- warnings.simplefilter('error', category=RemovedInNextVersionWarning)
- with self.assertRaisesMessage(RemovedInNextVersionWarning, msg):
- isinstance(object, Manager)
+ with self.assertWarnsMessage(RemovedInNextVersionWarning, msg):
+ isinstance(object, Manager)
diff --git a/tests/fixtures/tests.py b/tests/fixtures/tests.py
index a27ad6183d..d48062f8dd 100644
--- a/tests/fixtures/tests.py
+++ b/tests/fixtures/tests.py
@@ -495,16 +495,9 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
parent.
"""
ProxySpy.objects.create(name='Paul')
-
- with warnings.catch_warnings(record=True) as warning_list:
- warnings.simplefilter('always')
+ msg = "fixtures.ProxySpy is a proxy model and won't be serialized."
+ with self.assertWarnsMessage(ProxyModelWarning, msg):
self._dumpdata_assert(['fixtures.ProxySpy'], '[]')
- warning = warning_list.pop()
- self.assertEqual(warning.category, ProxyModelWarning)
- self.assertEqual(
- str(warning.message),
- "fixtures.ProxySpy is a proxy model and won't be serialized."
- )
def test_dumpdata_proxy_with_concrete(self):
"""
diff --git a/tests/fixtures_regress/tests.py b/tests/fixtures_regress/tests.py
index 3ca5084995..83b007bf59 100644
--- a/tests/fixtures_regress/tests.py
+++ b/tests/fixtures_regress/tests.py
@@ -2,7 +2,6 @@
import json
import os
import re
-import warnings
from io import StringIO
from django.core import management, serializers
@@ -209,19 +208,13 @@ class TestFixtures(TestCase):
using explicit filename.
Test for ticket #18213 -- warning conditions are caught correctly
"""
- with warnings.catch_warnings(record=True) as warning_list:
- warnings.simplefilter("always")
+ msg = "No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
+ with self.assertWarnsMessage(RuntimeWarning, msg):
management.call_command(
'loaddata',
'bad_fixture2.xml',
verbosity=0,
)
- warning = warning_list.pop()
- self.assertEqual(warning.category, RuntimeWarning)
- self.assertEqual(
- str(warning.message),
- "No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
- )
def test_invalid_data_no_ext(self):
"""
@@ -229,55 +222,40 @@ class TestFixtures(TestCase):
without file extension.
Test for ticket #18213 -- warning conditions are caught correctly
"""
- with warnings.catch_warnings(record=True) as warning_list:
- warnings.simplefilter("always")
+ msg = "No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
+ with self.assertWarnsMessage(RuntimeWarning, msg):
management.call_command(
'loaddata',
'bad_fixture2',
verbosity=0,
)
- warning = warning_list.pop()
- self.assertEqual(warning.category, RuntimeWarning)
- self.assertEqual(
- str(warning.message),
- "No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
- )
def test_empty(self):
"""
Test for ticket #18213 -- Loading a fixture file with no data output a warning.
Previously empty fixture raises an error exception, see ticket #4371.
"""
- with warnings.catch_warnings(record=True) as warning_list:
- warnings.simplefilter("always")
+ msg = "No fixture data found for 'empty'. (File format may be invalid.)"
+ with self.assertWarnsMessage(RuntimeWarning, msg):
management.call_command(
'loaddata',
'empty',
verbosity=0,
)
- warning = warning_list.pop()
- self.assertEqual(warning.category, RuntimeWarning)
- self.assertEqual(str(warning.message), "No fixture data found for 'empty'. (File format may be invalid.)")
def test_error_message(self):
"""
Regression for #9011 - error message is correct.
Change from error to warning for ticket #18213.
"""
- with warnings.catch_warnings(record=True) as warning_list:
- warnings.simplefilter("always")
+ msg = "No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
+ with self.assertWarnsMessage(RuntimeWarning, msg):
management.call_command(
'loaddata',
'bad_fixture2',
'animal',
verbosity=0,
)
- warning = warning_list.pop()
- self.assertEqual(warning.category, RuntimeWarning)
- self.assertEqual(
- str(warning.message),
- "No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
- )
def test_pg_sequence_resetting_checks(self):
"""
diff --git a/tests/forms_tests/tests/test_media.py b/tests/forms_tests/tests/test_media.py
index 9798fc027b..a586da90c5 100644
--- a/tests/forms_tests/tests/test_media.py
+++ b/tests/forms_tests/tests/test_media.py
@@ -1,5 +1,3 @@
-import warnings
-
from django.forms import CharField, Form, Media, MultiWidget, TextInput
from django.template import Context, Template
from django.test import SimpleTestCase, override_settings
@@ -540,10 +538,6 @@ class FormsMediaTestCase(SimpleTestCase):
self.assertEqual(Media.merge(list1, list2), expected)
def test_merge_warning(self):
- with warnings.catch_warnings(record=True) as w:
- warnings.simplefilter('always')
+ msg = 'Detected duplicate Media files in an opposite order:\n1\n2'
+ with self.assertWarnsMessage(RuntimeWarning, msg):
self.assertEqual(Media.merge([1, 2], [2, 1]), [1, 2])
- self.assertEqual(
- str(w[-1].message),
- 'Detected duplicate Media files in an opposite order:\n1\n2'
- )
diff --git a/tests/from_db_value/test_deprecated.py b/tests/from_db_value/test_deprecated.py
index f0e7ed92b7..75539b3a8d 100644
--- a/tests/from_db_value/test_deprecated.py
+++ b/tests/from_db_value/test_deprecated.py
@@ -1,6 +1,5 @@
-import warnings
-
from django.test import TestCase
+from django.utils.deprecation import RemovedInDjango30Warning
from .models import Cash, CashModelDeprecated
@@ -8,15 +7,11 @@ from .models import Cash, CashModelDeprecated
class FromDBValueDeprecationTests(TestCase):
def test_deprecation(self):
- CashModelDeprecated.objects.create(cash='12.50')
- with warnings.catch_warnings(record=True) as warns:
- warnings.simplefilter('always')
- instance = CashModelDeprecated.objects.get()
- self.assertIsInstance(instance.cash, Cash)
- self.assertEqual(len(warns), 1)
- msg = str(warns[0].message)
- self.assertEqual(
- msg,
+ msg = (
'Remove the context parameter from CashFieldDeprecated.from_db_value(). '
'Support for it will be removed in Django 3.0.'
)
+ CashModelDeprecated.objects.create(cash='12.50')
+ with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
+ instance = CashModelDeprecated.objects.get()
+ self.assertIsInstance(instance.cash, Cash)
diff --git a/tests/get_earliest_or_latest/tests.py b/tests/get_earliest_or_latest/tests.py
index 62f6f85ce2..a49dc43402 100644
--- a/tests/get_earliest_or_latest/tests.py
+++ b/tests/get_earliest_or_latest/tests.py
@@ -1,7 +1,7 @@
-import warnings
from datetime import datetime
from django.test import TestCase
+from django.utils.deprecation import RemovedInDjango30Warning
from .models import Article, IndexErrorArticle, Person
@@ -169,16 +169,12 @@ class EarliestOrLatestTests(TestCase):
def test_field_name_kwarg_deprecation(self):
Person.objects.create(name='Deprecator', birthday=datetime(1950, 1, 1))
- with warnings.catch_warnings(record=True) as warns:
- warnings.simplefilter('always')
- Person.objects.latest(field_name='birthday')
-
- self.assertEqual(len(warns), 1)
- self.assertEqual(
- str(warns[0].message),
+ msg = (
'The field_name keyword argument to earliest() and latest() '
- 'is deprecated in favor of passing positional arguments.',
+ 'is deprecated in favor of passing positional arguments.'
)
+ with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
+ Person.objects.latest(field_name='birthday')
class TestFirstLast(TestCase):
diff --git a/tests/migrations/test_graph.py b/tests/migrations/test_graph.py
index d4ab3685a9..884aaa70f7 100644
--- a/tests/migrations/test_graph.py
+++ b/tests/migrations/test_graph.py
@@ -1,5 +1,3 @@
-import warnings
-
from django.db.migrations.exceptions import (
CircularDependencyError, NodeNotFoundError,
)
@@ -193,22 +191,14 @@ class GraphTests(SimpleTestCase):
expected.append(child)
leaf = expected[-1]
- with warnings.catch_warnings(record=True) as w:
- warnings.simplefilter('always', RuntimeWarning)
+ with self.assertWarnsMessage(RuntimeWarning, RECURSION_DEPTH_WARNING):
forwards_plan = graph.forwards_plan(leaf)
- self.assertEqual(len(w), 1)
- self.assertTrue(issubclass(w[-1].category, RuntimeWarning))
- self.assertEqual(str(w[-1].message), RECURSION_DEPTH_WARNING)
self.assertEqual(expected, forwards_plan)
- with warnings.catch_warnings(record=True) as w:
- warnings.simplefilter('always', RuntimeWarning)
+ with self.assertWarnsMessage(RuntimeWarning, RECURSION_DEPTH_WARNING):
backwards_plan = graph.backwards_plan(root)
- self.assertEqual(len(w), 1)
- self.assertTrue(issubclass(w[-1].category, RuntimeWarning))
- self.assertEqual(str(w[-1].message), RECURSION_DEPTH_WARNING)
self.assertEqual(expected[::-1], backwards_plan)
def test_plan_invalid_node(self):
diff --git a/tests/modeladmin/test_has_add_permission_obj_deprecation.py b/tests/modeladmin/test_has_add_permission_obj_deprecation.py
index 6d48f210d1..18448e94d7 100644
--- a/tests/modeladmin/test_has_add_permission_obj_deprecation.py
+++ b/tests/modeladmin/test_has_add_permission_obj_deprecation.py
@@ -1,5 +1,3 @@
-import warnings
-
from django.contrib.admin.options import ModelAdmin, TabularInline
from django.utils.deprecation import RemovedInDjango30Warning
@@ -52,12 +50,9 @@ class HasAddPermissionObjTests(CheckTestCase):
class BandAdmin(ModelAdmin):
inlines = [SongInlineAdmin]
- with warnings.catch_warnings(record=True) as recorded:
- warnings.simplefilter('always')
- self.assertIsValid(BandAdmin, Band)
- self.assertEqual(len(recorded), 1)
- self.assertIs(recorded[0].category, RemovedInDjango30Warning)
- self.assertEqual(str(recorded[0].message), (
+ msg = (
"Update SongInlineAdmin.has_add_permission() to accept a "
"positional `obj` argument."
- ))
+ )
+ with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
+ self.assertIsValid(BandAdmin, Band)
diff --git a/tests/pagination/tests.py b/tests/pagination/tests.py
index 8be81240e8..f13afc308f 100644
--- a/tests/pagination/tests.py
+++ b/tests/pagination/tests.py
@@ -1,5 +1,4 @@
import unittest
-import warnings
from datetime import datetime
from django.core.paginator import (
@@ -359,20 +358,15 @@ class ModelPaginationTests(TestCase):
self.assertIsInstance(p.object_list, list)
def test_paginating_unordered_queryset_raises_warning(self):
- with warnings.catch_warnings(record=True) as warns:
- # Prevent the RuntimeWarning subclass from appearing as an
- # exception due to the warnings.simplefilter() in runtests.py.
- warnings.filterwarnings('always', category=UnorderedObjectListWarning)
- Paginator(Article.objects.all(), 5)
- self.assertEqual(len(warns), 1)
- warning = warns[0]
- self.assertEqual(str(warning.message), (
+ msg = (
"Pagination may yield inconsistent results with an unordered "
"object_list: <class 'pagination.models.Article'> QuerySet."
- ))
+ )
+ with self.assertWarnsMessage(UnorderedObjectListWarning, msg) as cm:
+ Paginator(Article.objects.all(), 5)
# The warning points at the Paginator caller (i.e. the stacklevel
# is appropriate).
- self.assertEqual(warning.filename, __file__)
+ self.assertEqual(cm.filename, __file__)
def test_paginating_unordered_object_list_raises_warning(self):
"""
@@ -382,11 +376,9 @@ class ModelPaginationTests(TestCase):
class ObjectList:
ordered = False
object_list = ObjectList()
- with warnings.catch_warnings(record=True) as warns:
- warnings.filterwarnings('always', category=UnorderedObjectListWarning)
- Paginator(object_list, 5)
- self.assertEqual(len(warns), 1)
- self.assertEqual(str(warns[0].message), (
+ msg = (
"Pagination may yield inconsistent results with an unordered "
"object_list: {!r}.".format(object_list)
- ))
+ )
+ with self.assertWarnsMessage(UnorderedObjectListWarning, msg):
+ Paginator(object_list, 5)
diff --git a/tests/settings_tests/tests.py b/tests/settings_tests/tests.py
index 9187f87388..53a9ea98f6 100644
--- a/tests/settings_tests/tests.py
+++ b/tests/settings_tests/tests.py
@@ -1,7 +1,6 @@
import os
import sys
import unittest
-import warnings
from types import ModuleType
from unittest import mock
@@ -349,15 +348,11 @@ class TestComplexSettingOverride(SimpleTestCase):
def test_complex_override_warning(self):
"""Regression test for #19031"""
- with warnings.catch_warnings(record=True) as w:
- warnings.simplefilter("always")
-
+ msg = 'Overriding setting TEST_WARN can lead to unexpected behavior.'
+ with self.assertWarnsMessage(UserWarning, msg) as cm:
with override_settings(TEST_WARN='override'):
self.assertEqual(settings.TEST_WARN, 'override')
-
- self.assertEqual(len(w), 1)
- self.assertEqual(w[0].filename, __file__)
- self.assertEqual(str(w[0].message), 'Overriding setting TEST_WARN can lead to unexpected behavior.')
+ self.assertEqual(cm.filename, __file__)
class SecureProxySslHeaderTest(SimpleTestCase):
diff --git a/tests/staticfiles_tests/test_templatetag_deprecation.py b/tests/staticfiles_tests/test_templatetag_deprecation.py
index 0194b0745e..898ee68093 100644
--- a/tests/staticfiles_tests/test_templatetag_deprecation.py
+++ b/tests/staticfiles_tests/test_templatetag_deprecation.py
@@ -1,4 +1,3 @@
-import warnings
from urllib.parse import urljoin
from django.contrib.staticfiles import storage
@@ -22,24 +21,16 @@ class StaticDeprecationTests(SimpleTestCase):
def test_templatetag_deprecated(self):
msg = '{% load staticfiles %} is deprecated in favor of {% load static %}.'
template = "{% load staticfiles %}{% static 'main.js' %}"
- with warnings.catch_warnings(record=True) as recorded:
- warnings.simplefilter('always')
+ with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
template = Template(template)
rendered = template.render(Context())
self.assertEqual(rendered, 'https://example.com/assets/main.js')
- self.assertEqual(len(recorded), 1)
- self.assertIs(recorded[0].category, RemovedInDjango30Warning)
- self.assertEqual(str(recorded[0].message), msg)
def test_static_deprecated(self):
msg = (
'django.contrib.staticfiles.templatetags.static() is deprecated in '
'favor of django.templatetags.static.static().'
)
- with warnings.catch_warnings(record=True) as recorded:
- warnings.simplefilter('always')
+ with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
url = static('main.js')
self.assertEqual(url, 'https://example.com/assets/main.js')
- self.assertEqual(len(recorded), 1)
- self.assertIs(recorded[0].category, RemovedInDjango30Warning)
- self.assertEqual(str(recorded[0].message), msg)
diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py
index dbb6cd573f..439ca0b7c7 100644
--- a/tests/test_utils/tests.py
+++ b/tests/test_utils/tests.py
@@ -1,5 +1,6 @@
import os
import unittest
+import warnings
from io import StringIO
from unittest import mock
@@ -864,6 +865,30 @@ class AssertRaisesMsgTest(SimpleTestCase):
func1()
+class AssertWarnsMessageTests(SimpleTestCase):
+
+ def test_context_manager(self):
+ with self.assertWarnsMessage(UserWarning, 'Expected message'):
+ warnings.warn('Expected message', UserWarning)
+
+ def test_context_manager_failure(self):
+ msg = "Expected message' not found in 'Unexpected message'"
+ with self.assertRaisesMessage(AssertionError, msg):
+ with self.assertWarnsMessage(UserWarning, 'Expected message'):
+ warnings.warn('Unexpected message', UserWarning)
+
+ def test_callable(self):
+ def func():
+ warnings.warn('Expected message', UserWarning)
+ self.assertWarnsMessage(UserWarning, 'Expected message', func)
+
+ def test_special_re_chars(self):
+ def func1():
+ warnings.warn('[.*x+]y?', UserWarning)
+ with self.assertWarnsMessage(UserWarning, '[.*x+]y?'):
+ func1()
+
+
class AssertFieldOutputTests(SimpleTestCase):
def test_assert_field_output(self):
diff --git a/tests/timezones/tests.py b/tests/timezones/tests.py
index 33b7897b82..3f7f70c7fb 100644
--- a/tests/timezones/tests.py
+++ b/tests/timezones/tests.py
@@ -1,7 +1,6 @@
import datetime
import re
import sys
-import warnings
from contextlib import contextmanager
from unittest import SkipTest, skipIf
from xml.dom.minidom import parseString
@@ -226,17 +225,13 @@ class LegacyDatabaseTests(TestCase):
@override_settings(TIME_ZONE='Africa/Nairobi', USE_TZ=True)
class NewDatabaseTests(TestCase):
+ naive_warning = 'DateTimeField Event.dt received a naive datetime'
@requires_tz_support
def test_naive_datetime(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
- with warnings.catch_warnings(record=True) as recorded:
- warnings.simplefilter('always')
+ with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
Event.objects.create(dt=dt)
- self.assertEqual(len(recorded), 1)
- msg = str(recorded[0].message)
- self.assertTrue(msg.startswith("DateTimeField Event.dt received "
- "a naive datetime"))
event = Event.objects.get()
# naive datetimes are interpreted in local time
self.assertEqual(event.dt, dt.replace(tzinfo=EAT))
@@ -244,26 +239,16 @@ class NewDatabaseTests(TestCase):
@requires_tz_support
def test_datetime_from_date(self):
dt = datetime.date(2011, 9, 1)
- with warnings.catch_warnings(record=True) as recorded:
- warnings.simplefilter('always')
+ with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
Event.objects.create(dt=dt)
- self.assertEqual(len(recorded), 1)
- msg = str(recorded[0].message)
- self.assertTrue(msg.startswith("DateTimeField Event.dt received "
- "a naive datetime"))
event = Event.objects.get()
self.assertEqual(event.dt, datetime.datetime(2011, 9, 1, tzinfo=EAT))
@requires_tz_support
def test_naive_datetime_with_microsecond(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
- with warnings.catch_warnings(record=True) as recorded:
- warnings.simplefilter('always')
+ with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
Event.objects.create(dt=dt)
- self.assertEqual(len(recorded), 1)
- msg = str(recorded[0].message)
- self.assertTrue(msg.startswith("DateTimeField Event.dt received "
- "a naive datetime"))
event = Event.objects.get()
# naive datetimes are interpreted in local time
self.assertEqual(event.dt, dt.replace(tzinfo=EAT))
@@ -330,17 +315,13 @@ class NewDatabaseTests(TestCase):
dt = datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=EAT)
Event.objects.create(dt=dt)
dt = dt.replace(tzinfo=None)
- with warnings.catch_warnings(record=True) as recorded:
- warnings.simplefilter('always')
- # naive datetimes are interpreted in local time
+ # naive datetimes are interpreted in local time
+ with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
self.assertEqual(Event.objects.filter(dt__exact=dt).count(), 1)
+ with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
self.assertEqual(Event.objects.filter(dt__lte=dt).count(), 1)
+ with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
self.assertEqual(Event.objects.filter(dt__gt=dt).count(), 0)
- self.assertEqual(len(recorded), 3)
- for warning in recorded:
- msg = str(warning.message)
- self.assertTrue(msg.startswith("DateTimeField Event.dt "
- "received a naive datetime"))
@skipUnlessDBFeature('has_zoneinfo_database')
def test_query_datetime_lookups(self):