mirror of https://github.com/django/django.git
Fixed #20004 -- Moved non DB-related assertions to SimpleTestCase.
Thanks zalew for the suggestion and work on a patch. Also updated, tweaked and fixed testing documentation.
This commit is contained in:
parent
69523c1ba3
commit
0a50311063
|
@ -231,6 +231,10 @@ class _AssertTemplateNotUsedContext(_AssertTemplateUsedContext):
|
|||
|
||||
class SimpleTestCase(ut2.TestCase):
|
||||
|
||||
# The class we'll use for the test client self.client.
|
||||
# Can be overridden in derived classes.
|
||||
client_class = Client
|
||||
|
||||
_warn_txt = ("save_warnings_state/restore_warnings_state "
|
||||
"django.test.*TestCase methods are deprecated. Use Python's "
|
||||
"warnings.catch_warnings context manager instead.")
|
||||
|
@ -264,10 +268,31 @@ class SimpleTestCase(ut2.TestCase):
|
|||
return
|
||||
|
||||
def _pre_setup(self):
|
||||
pass
|
||||
"""Performs any pre-test setup. This includes:
|
||||
|
||||
* If the Test Case class has a 'urls' member, replace the
|
||||
ROOT_URLCONF with it.
|
||||
* Clearing the mail test outbox.
|
||||
"""
|
||||
self.client = self.client_class()
|
||||
self._urlconf_setup()
|
||||
mail.outbox = []
|
||||
|
||||
def _urlconf_setup(self):
|
||||
set_urlconf(None)
|
||||
if hasattr(self, 'urls'):
|
||||
self._old_root_urlconf = settings.ROOT_URLCONF
|
||||
settings.ROOT_URLCONF = self.urls
|
||||
clear_url_caches()
|
||||
|
||||
def _post_teardown(self):
|
||||
pass
|
||||
self._urlconf_teardown()
|
||||
|
||||
def _urlconf_teardown(self):
|
||||
set_urlconf(None)
|
||||
if hasattr(self, '_old_root_urlconf'):
|
||||
settings.ROOT_URLCONF = self._old_root_urlconf
|
||||
clear_url_caches()
|
||||
|
||||
def save_warnings_state(self):
|
||||
"""
|
||||
|
@ -291,258 +316,6 @@ class SimpleTestCase(ut2.TestCase):
|
|||
"""
|
||||
return override_settings(**kwargs)
|
||||
|
||||
def assertRaisesMessage(self, expected_exception, expected_message,
|
||||
callable_obj=None, *args, **kwargs):
|
||||
"""
|
||||
Asserts that the message in a raised exception matches the passed
|
||||
value.
|
||||
|
||||
Args:
|
||||
expected_exception: Exception class expected to be raised.
|
||||
expected_message: expected error message string value.
|
||||
callable_obj: Function to be called.
|
||||
args: Extra args.
|
||||
kwargs: Extra kwargs.
|
||||
"""
|
||||
return six.assertRaisesRegex(self, expected_exception,
|
||||
re.escape(expected_message), callable_obj, *args, **kwargs)
|
||||
|
||||
def assertFieldOutput(self, fieldclass, valid, invalid, field_args=None,
|
||||
field_kwargs=None, empty_value=''):
|
||||
"""
|
||||
Asserts that a form field behaves correctly with various inputs.
|
||||
|
||||
Args:
|
||||
fieldclass: the class of the field to be tested.
|
||||
valid: a dictionary mapping valid inputs to their expected
|
||||
cleaned values.
|
||||
invalid: a dictionary mapping invalid inputs to one or more
|
||||
raised error messages.
|
||||
field_args: the args passed to instantiate the field
|
||||
field_kwargs: the kwargs passed to instantiate the field
|
||||
empty_value: the expected clean output for inputs in empty_values
|
||||
|
||||
"""
|
||||
if field_args is None:
|
||||
field_args = []
|
||||
if field_kwargs is None:
|
||||
field_kwargs = {}
|
||||
required = fieldclass(*field_args, **field_kwargs)
|
||||
optional = fieldclass(*field_args,
|
||||
**dict(field_kwargs, required=False))
|
||||
# test valid inputs
|
||||
for input, output in valid.items():
|
||||
self.assertEqual(required.clean(input), output)
|
||||
self.assertEqual(optional.clean(input), output)
|
||||
# test invalid inputs
|
||||
for input, errors in invalid.items():
|
||||
with self.assertRaises(ValidationError) as context_manager:
|
||||
required.clean(input)
|
||||
self.assertEqual(context_manager.exception.messages, errors)
|
||||
|
||||
with self.assertRaises(ValidationError) as context_manager:
|
||||
optional.clean(input)
|
||||
self.assertEqual(context_manager.exception.messages, errors)
|
||||
# test required inputs
|
||||
error_required = [force_text(required.error_messages['required'])]
|
||||
for e in required.empty_values:
|
||||
with self.assertRaises(ValidationError) as context_manager:
|
||||
required.clean(e)
|
||||
self.assertEqual(context_manager.exception.messages,
|
||||
error_required)
|
||||
self.assertEqual(optional.clean(e), empty_value)
|
||||
# test that max_length and min_length are always accepted
|
||||
if issubclass(fieldclass, CharField):
|
||||
field_kwargs.update({'min_length':2, 'max_length':20})
|
||||
self.assertTrue(isinstance(fieldclass(*field_args, **field_kwargs),
|
||||
fieldclass))
|
||||
|
||||
def assertHTMLEqual(self, html1, html2, msg=None):
|
||||
"""
|
||||
Asserts that two HTML snippets are semantically the same.
|
||||
Whitespace in most cases is ignored, and attribute ordering is not
|
||||
significant. The passed-in arguments must be valid HTML.
|
||||
"""
|
||||
dom1 = assert_and_parse_html(self, html1, msg,
|
||||
'First argument is not valid HTML:')
|
||||
dom2 = assert_and_parse_html(self, html2, msg,
|
||||
'Second argument is not valid HTML:')
|
||||
|
||||
if dom1 != dom2:
|
||||
standardMsg = '%s != %s' % (
|
||||
safe_repr(dom1, True), safe_repr(dom2, True))
|
||||
diff = ('\n' + '\n'.join(difflib.ndiff(
|
||||
six.text_type(dom1).splitlines(),
|
||||
six.text_type(dom2).splitlines())))
|
||||
standardMsg = self._truncateMessage(standardMsg, diff)
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertHTMLNotEqual(self, html1, html2, msg=None):
|
||||
"""Asserts that two HTML snippets are not semantically equivalent."""
|
||||
dom1 = assert_and_parse_html(self, html1, msg,
|
||||
'First argument is not valid HTML:')
|
||||
dom2 = assert_and_parse_html(self, html2, msg,
|
||||
'Second argument is not valid HTML:')
|
||||
|
||||
if dom1 == dom2:
|
||||
standardMsg = '%s == %s' % (
|
||||
safe_repr(dom1, True), safe_repr(dom2, True))
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertInHTML(self, needle, haystack, count = None, msg_prefix=''):
|
||||
needle = assert_and_parse_html(self, needle, None,
|
||||
'First argument is not valid HTML:')
|
||||
haystack = assert_and_parse_html(self, haystack, None,
|
||||
'Second argument is not valid HTML:')
|
||||
real_count = haystack.count(needle)
|
||||
if count is not None:
|
||||
self.assertEqual(real_count, count,
|
||||
msg_prefix + "Found %d instances of '%s' in response"
|
||||
" (expected %d)" % (real_count, needle, count))
|
||||
else:
|
||||
self.assertTrue(real_count != 0,
|
||||
msg_prefix + "Couldn't find '%s' in response" % needle)
|
||||
|
||||
def assertJSONEqual(self, raw, expected_data, msg=None):
|
||||
try:
|
||||
data = json.loads(raw)
|
||||
except ValueError:
|
||||
self.fail("First argument is not valid JSON: %r" % raw)
|
||||
if isinstance(expected_data, six.string_types):
|
||||
try:
|
||||
expected_data = json.loads(expected_data)
|
||||
except ValueError:
|
||||
self.fail("Second argument is not valid JSON: %r" % expected_data)
|
||||
self.assertEqual(data, expected_data, msg=msg)
|
||||
|
||||
def assertXMLEqual(self, xml1, xml2, msg=None):
|
||||
"""
|
||||
Asserts that two XML snippets are semantically the same.
|
||||
Whitespace in most cases is ignored, and attribute ordering is not
|
||||
significant. The passed-in arguments must be valid XML.
|
||||
"""
|
||||
try:
|
||||
result = compare_xml(xml1, xml2)
|
||||
except Exception as e:
|
||||
standardMsg = 'First or second argument is not valid XML\n%s' % e
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
else:
|
||||
if not result:
|
||||
standardMsg = '%s != %s' % (safe_repr(xml1, True), safe_repr(xml2, True))
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertXMLNotEqual(self, xml1, xml2, msg=None):
|
||||
"""
|
||||
Asserts that two XML snippets are not semantically equivalent.
|
||||
Whitespace in most cases is ignored, and attribute ordering is not
|
||||
significant. The passed-in arguments must be valid XML.
|
||||
"""
|
||||
try:
|
||||
result = compare_xml(xml1, xml2)
|
||||
except Exception as e:
|
||||
standardMsg = 'First or second argument is not valid XML\n%s' % e
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
else:
|
||||
if result:
|
||||
standardMsg = '%s == %s' % (safe_repr(xml1, True), safe_repr(xml2, True))
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
|
||||
class TransactionTestCase(SimpleTestCase):
|
||||
|
||||
# The class we'll use for the test client self.client.
|
||||
# Can be overridden in derived classes.
|
||||
client_class = Client
|
||||
|
||||
# Subclasses can ask for resetting of auto increment sequence before each
|
||||
# test case
|
||||
reset_sequences = False
|
||||
|
||||
def _pre_setup(self):
|
||||
"""Performs any pre-test setup. This includes:
|
||||
|
||||
* Flushing the database.
|
||||
* If the Test Case class has a 'fixtures' member, installing the
|
||||
named fixtures.
|
||||
* If the Test Case class has a 'urls' member, replace the
|
||||
ROOT_URLCONF with it.
|
||||
* Clearing the mail test outbox.
|
||||
"""
|
||||
self.client = self.client_class()
|
||||
self._fixture_setup()
|
||||
self._urlconf_setup()
|
||||
mail.outbox = []
|
||||
|
||||
def _databases_names(self, include_mirrors=True):
|
||||
# If the test case has a multi_db=True flag, act on all databases,
|
||||
# including mirrors or not. Otherwise, just on the default DB.
|
||||
if getattr(self, 'multi_db', False):
|
||||
return [alias for alias in connections
|
||||
if include_mirrors or not connections[alias].settings_dict['TEST_MIRROR']]
|
||||
else:
|
||||
return [DEFAULT_DB_ALIAS]
|
||||
|
||||
def _reset_sequences(self, db_name):
|
||||
conn = connections[db_name]
|
||||
if conn.features.supports_sequence_reset:
|
||||
sql_list = \
|
||||
conn.ops.sequence_reset_by_name_sql(no_style(),
|
||||
conn.introspection.sequence_list())
|
||||
if sql_list:
|
||||
with transaction.commit_on_success_unless_managed(using=db_name):
|
||||
cursor = conn.cursor()
|
||||
for sql in sql_list:
|
||||
cursor.execute(sql)
|
||||
|
||||
def _fixture_setup(self):
|
||||
for db_name in self._databases_names(include_mirrors=False):
|
||||
# Reset sequences
|
||||
if self.reset_sequences:
|
||||
self._reset_sequences(db_name)
|
||||
|
||||
if hasattr(self, 'fixtures'):
|
||||
# We have to use this slightly awkward syntax due to the fact
|
||||
# that we're using *args and **kwargs together.
|
||||
call_command('loaddata', *self.fixtures,
|
||||
**{'verbosity': 0, 'database': db_name, 'skip_validation': True})
|
||||
|
||||
def _urlconf_setup(self):
|
||||
set_urlconf(None)
|
||||
if hasattr(self, 'urls'):
|
||||
self._old_root_urlconf = settings.ROOT_URLCONF
|
||||
settings.ROOT_URLCONF = self.urls
|
||||
clear_url_caches()
|
||||
|
||||
def _post_teardown(self):
|
||||
""" Performs any post-test things. This includes:
|
||||
|
||||
* Putting back the original ROOT_URLCONF if it was changed.
|
||||
* Force closing the connection, so that the next test gets
|
||||
a clean cursor.
|
||||
"""
|
||||
self._fixture_teardown()
|
||||
self._urlconf_teardown()
|
||||
# Some DB cursors include SQL statements as part of cursor
|
||||
# creation. If you have a test that does rollback, the effect
|
||||
# of these statements is lost, which can effect the operation
|
||||
# of tests (e.g., losing a timezone setting causing objects to
|
||||
# be created with the wrong time).
|
||||
# To make sure this doesn't happen, get a clean connection at the
|
||||
# start of every test.
|
||||
for conn in connections.all():
|
||||
conn.close()
|
||||
|
||||
def _fixture_teardown(self):
|
||||
for db in self._databases_names(include_mirrors=False):
|
||||
call_command('flush', verbosity=0, interactive=False, database=db,
|
||||
skip_validation=True, reset_sequences=False)
|
||||
|
||||
def _urlconf_teardown(self):
|
||||
set_urlconf(None)
|
||||
if hasattr(self, '_old_root_urlconf'):
|
||||
settings.ROOT_URLCONF = self._old_root_urlconf
|
||||
clear_url_caches()
|
||||
|
||||
def assertRedirects(self, response, expected_url, status_code=302,
|
||||
target_status_code=200, host=None, msg_prefix=''):
|
||||
"""Asserts that a response redirected to a specific URL, and that the
|
||||
|
@ -787,6 +560,236 @@ class TransactionTestCase(SimpleTestCase):
|
|||
msg_prefix + "Template '%s' was used unexpectedly in rendering"
|
||||
" the response" % template_name)
|
||||
|
||||
def assertRaisesMessage(self, expected_exception, expected_message,
|
||||
callable_obj=None, *args, **kwargs):
|
||||
"""
|
||||
Asserts that the message in a raised exception matches the passed
|
||||
value.
|
||||
|
||||
Args:
|
||||
expected_exception: Exception class expected to be raised.
|
||||
expected_message: expected error message string value.
|
||||
callable_obj: Function to be called.
|
||||
args: Extra args.
|
||||
kwargs: Extra kwargs.
|
||||
"""
|
||||
return six.assertRaisesRegex(self, expected_exception,
|
||||
re.escape(expected_message), callable_obj, *args, **kwargs)
|
||||
|
||||
def assertFieldOutput(self, fieldclass, valid, invalid, field_args=None,
|
||||
field_kwargs=None, empty_value=''):
|
||||
"""
|
||||
Asserts that a form field behaves correctly with various inputs.
|
||||
|
||||
Args:
|
||||
fieldclass: the class of the field to be tested.
|
||||
valid: a dictionary mapping valid inputs to their expected
|
||||
cleaned values.
|
||||
invalid: a dictionary mapping invalid inputs to one or more
|
||||
raised error messages.
|
||||
field_args: the args passed to instantiate the field
|
||||
field_kwargs: the kwargs passed to instantiate the field
|
||||
empty_value: the expected clean output for inputs in empty_values
|
||||
|
||||
"""
|
||||
if field_args is None:
|
||||
field_args = []
|
||||
if field_kwargs is None:
|
||||
field_kwargs = {}
|
||||
required = fieldclass(*field_args, **field_kwargs)
|
||||
optional = fieldclass(*field_args,
|
||||
**dict(field_kwargs, required=False))
|
||||
# test valid inputs
|
||||
for input, output in valid.items():
|
||||
self.assertEqual(required.clean(input), output)
|
||||
self.assertEqual(optional.clean(input), output)
|
||||
# test invalid inputs
|
||||
for input, errors in invalid.items():
|
||||
with self.assertRaises(ValidationError) as context_manager:
|
||||
required.clean(input)
|
||||
self.assertEqual(context_manager.exception.messages, errors)
|
||||
|
||||
with self.assertRaises(ValidationError) as context_manager:
|
||||
optional.clean(input)
|
||||
self.assertEqual(context_manager.exception.messages, errors)
|
||||
# test required inputs
|
||||
error_required = [force_text(required.error_messages['required'])]
|
||||
for e in required.empty_values:
|
||||
with self.assertRaises(ValidationError) as context_manager:
|
||||
required.clean(e)
|
||||
self.assertEqual(context_manager.exception.messages,
|
||||
error_required)
|
||||
self.assertEqual(optional.clean(e), empty_value)
|
||||
# test that max_length and min_length are always accepted
|
||||
if issubclass(fieldclass, CharField):
|
||||
field_kwargs.update({'min_length':2, 'max_length':20})
|
||||
self.assertTrue(isinstance(fieldclass(*field_args, **field_kwargs),
|
||||
fieldclass))
|
||||
|
||||
def assertHTMLEqual(self, html1, html2, msg=None):
|
||||
"""
|
||||
Asserts that two HTML snippets are semantically the same.
|
||||
Whitespace in most cases is ignored, and attribute ordering is not
|
||||
significant. The passed-in arguments must be valid HTML.
|
||||
"""
|
||||
dom1 = assert_and_parse_html(self, html1, msg,
|
||||
'First argument is not valid HTML:')
|
||||
dom2 = assert_and_parse_html(self, html2, msg,
|
||||
'Second argument is not valid HTML:')
|
||||
|
||||
if dom1 != dom2:
|
||||
standardMsg = '%s != %s' % (
|
||||
safe_repr(dom1, True), safe_repr(dom2, True))
|
||||
diff = ('\n' + '\n'.join(difflib.ndiff(
|
||||
six.text_type(dom1).splitlines(),
|
||||
six.text_type(dom2).splitlines())))
|
||||
standardMsg = self._truncateMessage(standardMsg, diff)
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertHTMLNotEqual(self, html1, html2, msg=None):
|
||||
"""Asserts that two HTML snippets are not semantically equivalent."""
|
||||
dom1 = assert_and_parse_html(self, html1, msg,
|
||||
'First argument is not valid HTML:')
|
||||
dom2 = assert_and_parse_html(self, html2, msg,
|
||||
'Second argument is not valid HTML:')
|
||||
|
||||
if dom1 == dom2:
|
||||
standardMsg = '%s == %s' % (
|
||||
safe_repr(dom1, True), safe_repr(dom2, True))
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertInHTML(self, needle, haystack, count=None, msg_prefix=''):
|
||||
needle = assert_and_parse_html(self, needle, None,
|
||||
'First argument is not valid HTML:')
|
||||
haystack = assert_and_parse_html(self, haystack, None,
|
||||
'Second argument is not valid HTML:')
|
||||
real_count = haystack.count(needle)
|
||||
if count is not None:
|
||||
self.assertEqual(real_count, count,
|
||||
msg_prefix + "Found %d instances of '%s' in response"
|
||||
" (expected %d)" % (real_count, needle, count))
|
||||
else:
|
||||
self.assertTrue(real_count != 0,
|
||||
msg_prefix + "Couldn't find '%s' in response" % needle)
|
||||
|
||||
def assertJSONEqual(self, raw, expected_data, msg=None):
|
||||
try:
|
||||
data = json.loads(raw)
|
||||
except ValueError:
|
||||
self.fail("First argument is not valid JSON: %r" % raw)
|
||||
if isinstance(expected_data, six.string_types):
|
||||
try:
|
||||
expected_data = json.loads(expected_data)
|
||||
except ValueError:
|
||||
self.fail("Second argument is not valid JSON: %r" % expected_data)
|
||||
self.assertEqual(data, expected_data, msg=msg)
|
||||
|
||||
def assertXMLEqual(self, xml1, xml2, msg=None):
|
||||
"""
|
||||
Asserts that two XML snippets are semantically the same.
|
||||
Whitespace in most cases is ignored, and attribute ordering is not
|
||||
significant. The passed-in arguments must be valid XML.
|
||||
"""
|
||||
try:
|
||||
result = compare_xml(xml1, xml2)
|
||||
except Exception as e:
|
||||
standardMsg = 'First or second argument is not valid XML\n%s' % e
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
else:
|
||||
if not result:
|
||||
standardMsg = '%s != %s' % (safe_repr(xml1, True), safe_repr(xml2, True))
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertXMLNotEqual(self, xml1, xml2, msg=None):
|
||||
"""
|
||||
Asserts that two XML snippets are not semantically equivalent.
|
||||
Whitespace in most cases is ignored, and attribute ordering is not
|
||||
significant. The passed-in arguments must be valid XML.
|
||||
"""
|
||||
try:
|
||||
result = compare_xml(xml1, xml2)
|
||||
except Exception as e:
|
||||
standardMsg = 'First or second argument is not valid XML\n%s' % e
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
else:
|
||||
if result:
|
||||
standardMsg = '%s == %s' % (safe_repr(xml1, True), safe_repr(xml2, True))
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
|
||||
class TransactionTestCase(SimpleTestCase):
|
||||
|
||||
# Subclasses can ask for resetting of auto increment sequence before each
|
||||
# test case
|
||||
reset_sequences = False
|
||||
|
||||
def _pre_setup(self):
|
||||
"""Performs any pre-test setup. This includes:
|
||||
|
||||
* Flushing the database.
|
||||
* If the Test Case class has a 'fixtures' member, installing the
|
||||
named fixtures.
|
||||
"""
|
||||
super(TransactionTestCase, self)._pre_setup()
|
||||
self._fixture_setup()
|
||||
|
||||
def _databases_names(self, include_mirrors=True):
|
||||
# If the test case has a multi_db=True flag, act on all databases,
|
||||
# including mirrors or not. Otherwise, just on the default DB.
|
||||
if getattr(self, 'multi_db', False):
|
||||
return [alias for alias in connections
|
||||
if include_mirrors or not connections[alias].settings_dict['TEST_MIRROR']]
|
||||
else:
|
||||
return [DEFAULT_DB_ALIAS]
|
||||
|
||||
def _reset_sequences(self, db_name):
|
||||
conn = connections[db_name]
|
||||
if conn.features.supports_sequence_reset:
|
||||
sql_list = \
|
||||
conn.ops.sequence_reset_by_name_sql(no_style(),
|
||||
conn.introspection.sequence_list())
|
||||
if sql_list:
|
||||
with transaction.commit_on_success_unless_managed(using=db_name):
|
||||
cursor = conn.cursor()
|
||||
for sql in sql_list:
|
||||
cursor.execute(sql)
|
||||
|
||||
def _fixture_setup(self):
|
||||
for db_name in self._databases_names(include_mirrors=False):
|
||||
# Reset sequences
|
||||
if self.reset_sequences:
|
||||
self._reset_sequences(db_name)
|
||||
|
||||
if hasattr(self, 'fixtures'):
|
||||
# We have to use this slightly awkward syntax due to the fact
|
||||
# that we're using *args and **kwargs together.
|
||||
call_command('loaddata', *self.fixtures,
|
||||
**{'verbosity': 0, 'database': db_name, 'skip_validation': True})
|
||||
|
||||
def _post_teardown(self):
|
||||
"""Performs any post-test things. This includes:
|
||||
|
||||
* Putting back the original ROOT_URLCONF if it was changed.
|
||||
* Force closing the connection, so that the next test gets
|
||||
a clean cursor.
|
||||
"""
|
||||
self._fixture_teardown()
|
||||
super(TransactionTestCase, self)._post_teardown()
|
||||
# Some DB cursors include SQL statements as part of cursor
|
||||
# creation. If you have a test that does rollback, the effect
|
||||
# of these statements is lost, which can effect the operation
|
||||
# of tests (e.g., losing a timezone setting causing objects to
|
||||
# be created with the wrong time).
|
||||
# To make sure this doesn't happen, get a clean connection at the
|
||||
# start of every test.
|
||||
for conn in connections.all():
|
||||
conn.close()
|
||||
|
||||
def _fixture_teardown(self):
|
||||
for db_name in self._databases_names(include_mirrors=False):
|
||||
call_command('flush', verbosity=0, interactive=False, database=db_name,
|
||||
skip_validation=True, reset_sequences=False)
|
||||
|
||||
def assertQuerysetEqual(self, qs, values, transform=repr, ordered=True):
|
||||
items = six.moves.map(transform, qs)
|
||||
if not ordered:
|
||||
|
@ -841,14 +844,14 @@ class TestCase(TransactionTestCase):
|
|||
# Remove this when the legacy transaction management goes away.
|
||||
disable_transaction_methods()
|
||||
|
||||
for db in self._databases_names(include_mirrors=False):
|
||||
for db_name in self._databases_names(include_mirrors=False):
|
||||
if hasattr(self, 'fixtures'):
|
||||
try:
|
||||
call_command('loaddata', *self.fixtures,
|
||||
**{
|
||||
'verbosity': 0,
|
||||
'commit': False,
|
||||
'database': db,
|
||||
'database': db_name,
|
||||
'skip_validation': True,
|
||||
})
|
||||
except Exception:
|
||||
|
|
|
@ -503,8 +503,8 @@ of the process of creating polls.
|
|||
message: "No polls are available." and verifies the ``latest_poll_list`` is
|
||||
empty. Note that the :class:`django.test.TestCase` class provides some
|
||||
additional assertion methods. In these examples, we use
|
||||
:meth:`~django.test.TestCase.assertContains()` and
|
||||
:meth:`~django.test.TestCase.assertQuerysetEqual()`.
|
||||
:meth:`~django.test.SimpleTestCase.assertContains()` and
|
||||
:meth:`~django.test.TransactionTestCase.assertQuerysetEqual()`.
|
||||
|
||||
In ``test_index_view_with_a_past_poll``, we create a poll and verify that it
|
||||
appears in the list.
|
||||
|
|
|
@ -329,7 +329,7 @@ model:
|
|||
.. admonition:: Serializing references to ``ContentType`` objects
|
||||
|
||||
If you're serializing data (for example, when generating
|
||||
:class:`~django.test.TestCase.fixtures`) from a model that implements
|
||||
:class:`~django.test.TransactionTestCase.fixtures`) from a model that implements
|
||||
generic relations, you should probably be using a natural key to uniquely
|
||||
identify related :class:`~django.contrib.contenttypes.models.ContentType`
|
||||
objects. See :ref:`natural keys<topics-serialization-natural-keys>` and
|
||||
|
|
|
@ -154,7 +154,7 @@ requests. These include:
|
|||
requests in tests.
|
||||
|
||||
* A new test assertion --
|
||||
:meth:`~django.test.TestCase.assertNumQueries` -- making it
|
||||
:meth:`~django.test.TransactionTestCase.assertNumQueries` -- making it
|
||||
easier to test the database activity associated with a view.
|
||||
|
||||
|
||||
|
|
|
@ -299,7 +299,7 @@ requests. These include:
|
|||
in tests.
|
||||
|
||||
* A new test assertion --
|
||||
:meth:`~django.test.TestCase.assertNumQueries` -- making it
|
||||
:meth:`~django.test.TransactionTestCase.assertNumQueries` -- making it
|
||||
easier to test the database activity associated with a view.
|
||||
|
||||
* Support for lookups spanning relations in admin's
|
||||
|
|
|
@ -541,8 +541,8 @@ compare HTML directly with the new
|
|||
:meth:`~django.test.SimpleTestCase.assertHTMLEqual` and
|
||||
:meth:`~django.test.SimpleTestCase.assertHTMLNotEqual` assertions, or use
|
||||
the ``html=True`` flag with
|
||||
:meth:`~django.test.TestCase.assertContains` and
|
||||
:meth:`~django.test.TestCase.assertNotContains` to test whether the
|
||||
:meth:`~django.test.SimpleTestCase.assertContains` and
|
||||
:meth:`~django.test.SimpleTestCase.assertNotContains` to test whether the
|
||||
client's response contains a given HTML fragment. See the :ref:`assertions
|
||||
documentation <assertions>` for more.
|
||||
|
||||
|
@ -1093,8 +1093,8 @@ wild, because they would confuse browsers too.
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It's now possible to check whether a template was used within a block of
|
||||
code with :meth:`~django.test.TestCase.assertTemplateUsed` and
|
||||
:meth:`~django.test.TestCase.assertTemplateNotUsed`. And they
|
||||
code with :meth:`~django.test.SimpleTestCase.assertTemplateUsed` and
|
||||
:meth:`~django.test.SimpleTestCase.assertTemplateNotUsed`. And they
|
||||
can be used as a context manager::
|
||||
|
||||
with self.assertTemplateUsed('index.html'):
|
||||
|
|
|
@ -271,9 +271,10 @@ The changes in transaction management may result in additional statements to
|
|||
create, release or rollback savepoints. This is more likely to happen with
|
||||
SQLite, since it didn't support savepoints until this release.
|
||||
|
||||
If tests using :meth:`~django.test.TestCase.assertNumQueries` fail because of
|
||||
a higher number of queries than expected, check that the extra queries are
|
||||
related to savepoints, and adjust the expected number of queries accordingly.
|
||||
If tests using :meth:`~django.test.TransactionTestCase.assertNumQueries` fail
|
||||
because of a higher number of queries than expected, check that the extra
|
||||
queries are related to savepoints, and adjust the expected number of queries
|
||||
accordingly.
|
||||
|
||||
Autocommit option for PostgreSQL
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -201,8 +201,8 @@ According to :pep:`3333`:
|
|||
Specifically, :attr:`HttpResponse.content <django.http.HttpResponse.content>`
|
||||
contains ``bytes``, which may become an issue if you compare it with a
|
||||
``str`` in your tests. The preferred solution is to rely on
|
||||
:meth:`~django.test.TestCase.assertContains` and
|
||||
:meth:`~django.test.TestCase.assertNotContains`. These methods accept a
|
||||
:meth:`~django.test.SimpleTestCase.assertContains` and
|
||||
:meth:`~django.test.SimpleTestCase.assertNotContains`. These methods accept a
|
||||
response and a unicode string as arguments.
|
||||
|
||||
Coding guidelines
|
||||
|
|
|
@ -21,17 +21,16 @@ module defines tests using a class-based approach.
|
|||
|
||||
.. admonition:: unittest2
|
||||
|
||||
Python 2.7 introduced some major changes to the unittest library,
|
||||
Python 2.7 introduced some major changes to the ``unittest`` library,
|
||||
adding some extremely useful features. To ensure that every Django
|
||||
project can benefit from these new features, Django ships with a
|
||||
copy of unittest2_, a copy of the Python 2.7 unittest library,
|
||||
backported for Python 2.6 compatibility.
|
||||
copy of unittest2_, a copy of Python 2.7's ``unittest``, backported for
|
||||
Python 2.6 compatibility.
|
||||
|
||||
To access this library, Django provides the
|
||||
``django.utils.unittest`` module alias. If you are using Python
|
||||
2.7, or you have installed unittest2 locally, Django will map the
|
||||
alias to the installed version of the unittest library. Otherwise,
|
||||
Django will use its own bundled version of unittest2.
|
||||
2.7, or you have installed ``unittest2`` locally, Django will map the alias
|
||||
to it. Otherwise, Django will use its own bundled version of ``unittest2``.
|
||||
|
||||
To use this alias, simply use::
|
||||
|
||||
|
@ -41,8 +40,8 @@ module defines tests using a class-based approach.
|
|||
|
||||
import unittest
|
||||
|
||||
If you want to continue to use the base unittest library, you can --
|
||||
you just won't get any of the nice new unittest2 features.
|
||||
If you want to continue to use the legacy ``unittest`` library, you can --
|
||||
you just won't get any of the nice new ``unittest2`` features.
|
||||
|
||||
.. _unittest2: http://pypi.python.org/pypi/unittest2
|
||||
|
||||
|
@ -858,24 +857,46 @@ SimpleTestCase
|
|||
|
||||
.. class:: SimpleTestCase()
|
||||
|
||||
A very thin subclass of :class:`unittest.TestCase`, it extends it with some
|
||||
basic functionality like:
|
||||
A thin subclass of :class:`unittest.TestCase`, it extends it with some basic
|
||||
functionality like:
|
||||
|
||||
* Saving and restoring the Python warning machinery state.
|
||||
* Checking that a callable :meth:`raises a certain exception <SimpleTestCase.assertRaisesMessage>`.
|
||||
* :meth:`Testing form field rendering <SimpleTestCase.assertFieldOutput>`.
|
||||
* Testing server :ref:`HTML responses for the presence/lack of a given fragment <assertions>`.
|
||||
* The ability to run tests with :ref:`modified settings <overriding-settings>`
|
||||
* Some useful assertions like:
|
||||
|
||||
* Checking that a callable :meth:`raises a certain exception
|
||||
<SimpleTestCase.assertRaisesMessage>`.
|
||||
* Testing form field :meth:`rendering and error treatment
|
||||
<SimpleTestCase.assertFieldOutput>`.
|
||||
* Testing :meth:`HTML responses for the presence/lack of a given fragment
|
||||
<SimpleTestCase.assertContains>`.
|
||||
* Verifying that a template :meth:`has/hasn't been used to generate a given
|
||||
response content <SimpleTestCase.assertTemplateUsed>`.
|
||||
* Verifying a HTTP :meth:`redirect <SimpleTestCase.assertRedirects>` is
|
||||
performed by the app.
|
||||
* Robustly testing two :meth:`HTML fragments <SimpleTestCase.assertHTMLEqual>`
|
||||
for equality/inequality or :meth:`containment <SimpleTestCase.assertInHTML>`.
|
||||
* Robustly testing two :meth:`XML fragments <SimpleTestCase.assertXMLEqual>`
|
||||
for equality/inequality.
|
||||
* Robustly testing two :meth:`JSON fragments <SimpleTestCase.assertJSONEqual>`
|
||||
for equality.
|
||||
|
||||
* The ability to run tests with :ref:`modified settings <overriding-settings>`.
|
||||
* Using the :attr:`~SimpleTestCase.client` :class:`~django.test.client.Client`.
|
||||
* Custom test-time :attr:`URL maps <SimpleTestCase.urls>`.
|
||||
|
||||
.. versionchanged:: 1.6
|
||||
|
||||
The latter two features were moved from ``TransactionTestCase`` to
|
||||
``SimpleTestCase`` in Django 1.6.
|
||||
|
||||
If you need any of the other more complex and heavyweight Django-specific
|
||||
features like:
|
||||
|
||||
* Using the :attr:`~TestCase.client` :class:`~django.test.client.Client`.
|
||||
* Testing or using the ORM.
|
||||
* Database :attr:`~TestCase.fixtures`.
|
||||
* Custom test-time :attr:`URL maps <TestCase.urls>`.
|
||||
* Database :attr:`~TransactionTestCase.fixtures`.
|
||||
* Test :ref:`skipping based on database backend features <skipping-tests>`.
|
||||
* The remaining specialized :ref:`assert* <assertions>` methods.
|
||||
* The remaining specialized :meth:`assert*
|
||||
<TransactionTestCase.assertQuerysetEqual>` methods.
|
||||
|
||||
then you should use :class:`~django.test.TransactionTestCase` or
|
||||
:class:`~django.test.TestCase` instead.
|
||||
|
@ -1137,9 +1158,9 @@ Test cases features
|
|||
Default test client
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. attribute:: TestCase.client
|
||||
.. attribute:: SimpleTestCase.client
|
||||
|
||||
Every test case in a ``django.test.TestCase`` instance has access to an
|
||||
Every test case in a ``django.test.*TestCase`` instance has access to an
|
||||
instance of a Django test client. This client can be accessed as
|
||||
``self.client``. This client is recreated for each test, so you don't have to
|
||||
worry about state (such as cookies) carrying over from one test to another.
|
||||
|
@ -1176,10 +1197,10 @@ This means, instead of instantiating a ``Client`` in each test::
|
|||
Customizing the test client
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. attribute:: TestCase.client_class
|
||||
.. attribute:: SimpleTestCase.client_class
|
||||
|
||||
If you want to use a different ``Client`` class (for example, a subclass
|
||||
with customized behavior), use the :attr:`~TestCase.client_class` class
|
||||
with customized behavior), use the :attr:`~SimpleTestCase.client_class` class
|
||||
attribute::
|
||||
|
||||
from django.test import TestCase
|
||||
|
@ -1200,11 +1221,12 @@ attribute::
|
|||
Fixture loading
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.. attribute:: TestCase.fixtures
|
||||
.. attribute:: TransactionTestCase.fixtures
|
||||
|
||||
A test case for a database-backed Web site isn't much use if there isn't any
|
||||
data in the database. To make it easy to put test data into the database,
|
||||
Django's custom ``TestCase`` class provides a way of loading **fixtures**.
|
||||
Django's custom ``TransactionTestCase`` class provides a way of loading
|
||||
**fixtures**.
|
||||
|
||||
A fixture is a collection of data that Django knows how to import into a
|
||||
database. For example, if your site has user accounts, you might set up a
|
||||
|
@ -1273,7 +1295,7 @@ or by the order of test execution.
|
|||
URLconf configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. attribute:: TestCase.urls
|
||||
.. attribute:: SimpleTestCase.urls
|
||||
|
||||
If your application provides views, you may want to include tests that use the
|
||||
test client to exercise those views. However, an end user is free to deploy the
|
||||
|
@ -1282,9 +1304,9 @@ tests can't rely upon the fact that your views will be available at a
|
|||
particular URL.
|
||||
|
||||
In order to provide a reliable URL space for your test,
|
||||
``django.test.TestCase`` provides the ability to customize the URLconf
|
||||
``django.test.*TestCase`` classes provide the ability to customize the URLconf
|
||||
configuration for the duration of the execution of a test suite. If your
|
||||
``TestCase`` instance defines an ``urls`` attribute, the ``TestCase`` will use
|
||||
``*TestCase`` instance defines an ``urls`` attribute, the ``*TestCase`` will use
|
||||
the value of that attribute as the :setting:`ROOT_URLCONF` for the duration
|
||||
of that test.
|
||||
|
||||
|
@ -1307,7 +1329,7 @@ URLconf for the duration of the test case.
|
|||
Multi-database support
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. attribute:: TestCase.multi_db
|
||||
.. attribute:: TransactionTestCase.multi_db
|
||||
|
||||
Django sets up a test database corresponding to every database that is
|
||||
defined in the :setting:`DATABASES` definition in your settings
|
||||
|
@ -1340,12 +1362,12 @@ This test case will flush *all* the test databases before running
|
|||
Overriding settings
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. method:: TestCase.settings
|
||||
.. method:: SimpleTestCase.settings
|
||||
|
||||
For testing purposes it's often useful to change a setting temporarily and
|
||||
revert to the original value after running the testing code. For this use case
|
||||
Django provides a standard Python context manager (see :pep:`343`)
|
||||
:meth:`~django.test.TestCase.settings`, which can be used like this::
|
||||
:meth:`~django.test.SimpleTestCase.settings`, which can be used like this::
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
|
@ -1435,8 +1457,8 @@ MEDIA_ROOT, DEFAULT_FILE_STORAGE Default file storage
|
|||
Emptying the test outbox
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you use Django's custom ``TestCase`` class, the test runner will clear the
|
||||
contents of the test email outbox at the start of each test case.
|
||||
If you use any of Django's custom ``TestCase`` classes, the test runner will
|
||||
clear thecontents of the test email outbox at the start of each test case.
|
||||
|
||||
For more detail on email services during tests, see `Email services`_ below.
|
||||
|
||||
|
@ -1486,31 +1508,7 @@ your test suite.
|
|||
|
||||
self.assertFieldOutput(EmailField, {'a@a.com': 'a@a.com'}, {'aaa': [u'Enter a valid email address.']})
|
||||
|
||||
|
||||
.. method:: TestCase.assertContains(response, text, count=None, status_code=200, msg_prefix='', html=False)
|
||||
|
||||
Asserts that a ``Response`` instance produced the given ``status_code`` and
|
||||
that ``text`` appears in the content of the response. If ``count`` is
|
||||
provided, ``text`` must occur exactly ``count`` times in the response.
|
||||
|
||||
Set ``html`` to ``True`` to handle ``text`` as HTML. The comparison with
|
||||
the response content will be based on HTML semantics instead of
|
||||
character-by-character equality. Whitespace is ignored in most cases,
|
||||
attribute ordering is not significant. See
|
||||
:meth:`~SimpleTestCase.assertHTMLEqual` for more details.
|
||||
|
||||
.. method:: TestCase.assertNotContains(response, text, status_code=200, msg_prefix='', html=False)
|
||||
|
||||
Asserts that a ``Response`` instance produced the given ``status_code`` and
|
||||
that ``text`` does not appears in the content of the response.
|
||||
|
||||
Set ``html`` to ``True`` to handle ``text`` as HTML. The comparison with
|
||||
the response content will be based on HTML semantics instead of
|
||||
character-by-character equality. Whitespace is ignored in most cases,
|
||||
attribute ordering is not significant. See
|
||||
:meth:`~SimpleTestCase.assertHTMLEqual` for more details.
|
||||
|
||||
.. method:: TestCase.assertFormError(response, form, field, errors, msg_prefix='')
|
||||
.. method:: SimpleTestCase.assertFormError(response, form, field, errors, msg_prefix='')
|
||||
|
||||
Asserts that a field on a form raises the provided list of errors when
|
||||
rendered on the form.
|
||||
|
@ -1525,7 +1523,30 @@ your test suite.
|
|||
``errors`` is an error string, or a list of error strings, that are
|
||||
expected as a result of form validation.
|
||||
|
||||
.. method:: TestCase.assertTemplateUsed(response, template_name, msg_prefix='')
|
||||
.. method:: SimpleTestCase.assertContains(response, text, count=None, status_code=200, msg_prefix='', html=False)
|
||||
|
||||
Asserts that a ``Response`` instance produced the given ``status_code`` and
|
||||
that ``text`` appears in the content of the response. If ``count`` is
|
||||
provided, ``text`` must occur exactly ``count`` times in the response.
|
||||
|
||||
Set ``html`` to ``True`` to handle ``text`` as HTML. The comparison with
|
||||
the response content will be based on HTML semantics instead of
|
||||
character-by-character equality. Whitespace is ignored in most cases,
|
||||
attribute ordering is not significant. See
|
||||
:meth:`~SimpleTestCase.assertHTMLEqual` for more details.
|
||||
|
||||
.. method:: SimpleTestCase.assertNotContains(response, text, status_code=200, msg_prefix='', html=False)
|
||||
|
||||
Asserts that a ``Response`` instance produced the given ``status_code`` and
|
||||
that ``text`` does not appears in the content of the response.
|
||||
|
||||
Set ``html`` to ``True`` to handle ``text`` as HTML. The comparison with
|
||||
the response content will be based on HTML semantics instead of
|
||||
character-by-character equality. Whitespace is ignored in most cases,
|
||||
attribute ordering is not significant. See
|
||||
:meth:`~SimpleTestCase.assertHTMLEqual` for more details.
|
||||
|
||||
.. method:: SimpleTestCase.assertTemplateUsed(response, template_name, msg_prefix='')
|
||||
|
||||
Asserts that the template with the given name was used in rendering the
|
||||
response.
|
||||
|
@ -1539,15 +1560,15 @@ your test suite.
|
|||
with self.assertTemplateUsed(template_name='index.html'):
|
||||
render_to_string('index.html')
|
||||
|
||||
.. method:: TestCase.assertTemplateNotUsed(response, template_name, msg_prefix='')
|
||||
.. method:: SimpleTestCase.assertTemplateNotUsed(response, template_name, msg_prefix='')
|
||||
|
||||
Asserts that the template with the given name was *not* used in rendering
|
||||
the response.
|
||||
|
||||
You can use this as a context manager in the same way as
|
||||
:meth:`~TestCase.assertTemplateUsed`.
|
||||
:meth:`~SimpleTestCase.assertTemplateUsed`.
|
||||
|
||||
.. method:: TestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='')
|
||||
.. method:: SimpleTestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='')
|
||||
|
||||
Asserts that the response return a ``status_code`` redirect status, it
|
||||
redirected to ``expected_url`` (including any GET data), and the final
|
||||
|
@ -1557,44 +1578,6 @@ your test suite.
|
|||
``target_status_code`` will be the url and status code for the final
|
||||
point of the redirect chain.
|
||||
|
||||
.. method:: TestCase.assertQuerysetEqual(qs, values, transform=repr, ordered=True)
|
||||
|
||||
Asserts that a queryset ``qs`` returns a particular list of values ``values``.
|
||||
|
||||
The comparison of the contents of ``qs`` and ``values`` is performed using
|
||||
the function ``transform``; by default, this means that the ``repr()`` of
|
||||
each value is compared. Any other callable can be used if ``repr()`` doesn't
|
||||
provide a unique or helpful comparison.
|
||||
|
||||
By default, the comparison is also ordering dependent. If ``qs`` doesn't
|
||||
provide an implicit ordering, you can set the ``ordered`` parameter to
|
||||
``False``, which turns the comparison into a Python set comparison.
|
||||
|
||||
.. versionchanged:: 1.6
|
||||
|
||||
The method now checks for undefined order and raises ``ValueError``
|
||||
if undefined order is spotted. The ordering is seen as undefined if
|
||||
the given ``qs`` isn't ordered and the comparison is against more
|
||||
than one ordered values.
|
||||
|
||||
.. method:: TestCase.assertNumQueries(num, func, *args, **kwargs)
|
||||
|
||||
Asserts that when ``func`` is called with ``*args`` and ``**kwargs`` that
|
||||
``num`` database queries are executed.
|
||||
|
||||
If a ``"using"`` key is present in ``kwargs`` it is used as the database
|
||||
alias for which to check the number of queries. If you wish to call a
|
||||
function with a ``using`` parameter you can do it by wrapping the call with
|
||||
a ``lambda`` to add an extra parameter::
|
||||
|
||||
self.assertNumQueries(7, lambda: my_function(using=7))
|
||||
|
||||
You can also use this as a context manager::
|
||||
|
||||
with self.assertNumQueries(2):
|
||||
Person.objects.create(name="Aaron")
|
||||
Person.objects.create(name="Daniel")
|
||||
|
||||
.. method:: SimpleTestCase.assertHTMLEqual(html1, html2, msg=None)
|
||||
|
||||
Asserts that the strings ``html1`` and ``html2`` are equal. The comparison
|
||||
|
@ -1624,6 +1607,8 @@ your test suite.
|
|||
``html1`` and ``html2`` must be valid HTML. An ``AssertionError`` will be
|
||||
raised if one of them cannot be parsed.
|
||||
|
||||
Output in case of error can be customized with the ``msg`` argument.
|
||||
|
||||
.. method:: SimpleTestCase.assertHTMLNotEqual(html1, html2, msg=None)
|
||||
|
||||
Asserts that the strings ``html1`` and ``html2`` are *not* equal. The
|
||||
|
@ -1633,6 +1618,8 @@ your test suite.
|
|||
``html1`` and ``html2`` must be valid HTML. An ``AssertionError`` will be
|
||||
raised if one of them cannot be parsed.
|
||||
|
||||
Output in case of error can be customized with the ``msg`` argument.
|
||||
|
||||
.. method:: SimpleTestCase.assertXMLEqual(xml1, xml2, msg=None)
|
||||
|
||||
.. versionadded:: 1.5
|
||||
|
@ -1644,6 +1631,8 @@ your test suite.
|
|||
syntax differences. When unvalid XML is passed in any parameter, an
|
||||
``AssertionError`` is always raised, even if both string are identical.
|
||||
|
||||
Output in case of error can be customized with the ``msg`` argument.
|
||||
|
||||
.. method:: SimpleTestCase.assertXMLNotEqual(xml1, xml2, msg=None)
|
||||
|
||||
.. versionadded:: 1.5
|
||||
|
@ -1652,6 +1641,68 @@ your test suite.
|
|||
comparison is based on XML semantics. See
|
||||
:meth:`~SimpleTestCase.assertXMLEqual` for details.
|
||||
|
||||
Output in case of error can be customized with the ``msg`` argument.
|
||||
|
||||
.. method:: SimpleTestCase.assertInHTML(needle, haystack, count=None, msg_prefix='')
|
||||
|
||||
.. versionadded:: 1.5
|
||||
|
||||
Asserts that the HTML fragment ``needle`` is contained in the ``haystack`` one.
|
||||
|
||||
If the ``count`` integer argument is specified, then additionally the number
|
||||
of ``needle`` occurrences will be strictly verified.
|
||||
|
||||
Whitespace in most cases is ignored, and attribute ordering is not
|
||||
significant. The passed-in arguments must be valid HTML.
|
||||
|
||||
.. method:: SimpleTestCase.assertJSONEqual(raw, expected_data, msg=None)
|
||||
|
||||
.. versionadded:: 1.5
|
||||
|
||||
Asserts that the JSON fragments ``raw`` and ``expected_data`` are equal.
|
||||
Usual JSON non-significant whitespace rules apply as the heavyweight is
|
||||
delegated to the :mod:`json` library.
|
||||
|
||||
Output in case of error can be customized with the ``msg`` argument.
|
||||
|
||||
.. method:: TransactionTestCase.assertQuerysetEqual(qs, values, transform=repr, ordered=True)
|
||||
|
||||
Asserts that a queryset ``qs`` returns a particular list of values ``values``.
|
||||
|
||||
The comparison of the contents of ``qs`` and ``values`` is performed using
|
||||
the function ``transform``; by default, this means that the ``repr()`` of
|
||||
each value is compared. Any other callable can be used if ``repr()`` doesn't
|
||||
provide a unique or helpful comparison.
|
||||
|
||||
By default, the comparison is also ordering dependent. If ``qs`` doesn't
|
||||
provide an implicit ordering, you can set the ``ordered`` parameter to
|
||||
``False``, which turns the comparison into a Python set comparison.
|
||||
|
||||
.. versionchanged:: 1.6
|
||||
|
||||
The method now checks for undefined order and raises ``ValueError``
|
||||
if undefined order is spotted. The ordering is seen as undefined if
|
||||
the given ``qs`` isn't ordered and the comparison is against more
|
||||
than one ordered values.
|
||||
|
||||
.. method:: TransactionTestCase.assertNumQueries(num, func, *args, **kwargs)
|
||||
|
||||
Asserts that when ``func`` is called with ``*args`` and ``**kwargs`` that
|
||||
``num`` database queries are executed.
|
||||
|
||||
If a ``"using"`` key is present in ``kwargs`` it is used as the database
|
||||
alias for which to check the number of queries. If you wish to call a
|
||||
function with a ``using`` parameter you can do it by wrapping the call with
|
||||
a ``lambda`` to add an extra parameter::
|
||||
|
||||
self.assertNumQueries(7, lambda: my_function(using=7))
|
||||
|
||||
You can also use this as a context manager::
|
||||
|
||||
with self.assertNumQueries(2):
|
||||
Person.objects.create(name="Aaron")
|
||||
Person.objects.create(name="Daniel")
|
||||
|
||||
.. _topics-testing-email:
|
||||
|
||||
Email services
|
||||
|
@ -1701,7 +1752,7 @@ and contents::
|
|||
self.assertEqual(mail.outbox[0].subject, 'Subject here')
|
||||
|
||||
As noted :ref:`previously <emptying-test-outbox>`, the test outbox is emptied
|
||||
at the start of every test in a Django ``TestCase``. To empty the outbox
|
||||
at the start of every test in a Django ``*TestCase``. To empty the outbox
|
||||
manually, assign the empty list to ``mail.outbox``::
|
||||
|
||||
from django.core import mail
|
||||
|
|
Loading…
Reference in New Issue