Make BulkAssertionTest.bulk_assertions work with any assert* method
This commit is contained in:
@@ -7,35 +7,35 @@ Run like this:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import inspect
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import pprint
|
import pprint
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
import unittest
|
import unittest
|
||||||
import inspect
|
|
||||||
import mock
|
|
||||||
|
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager, nested
|
||||||
from lazy import lazy
|
|
||||||
from mock import Mock
|
|
||||||
from operator import attrgetter
|
|
||||||
from path import path
|
|
||||||
from eventtracking import tracker
|
from eventtracking import tracker
|
||||||
from eventtracking.django import DjangoTracker
|
from eventtracking.django import DjangoTracker
|
||||||
|
from functools import wraps
|
||||||
|
from lazy import lazy
|
||||||
|
from mock import Mock, patch
|
||||||
|
from operator import attrgetter
|
||||||
|
from path import path
|
||||||
|
|
||||||
|
from opaque_keys.edx.locations import SlashSeparatedCourseKey
|
||||||
from xblock.field_data import DictFieldData
|
from xblock.field_data import DictFieldData
|
||||||
from xblock.fields import ScopeIds, Scope, Reference, ReferenceList, ReferenceValueDict
|
from xblock.fields import ScopeIds, Scope, Reference, ReferenceList, ReferenceValueDict
|
||||||
|
|
||||||
from xmodule.x_module import ModuleSystem, XModuleDescriptor, XModuleMixin
|
|
||||||
from xmodule.modulestore.inheritance import InheritanceMixin, own_metadata
|
|
||||||
from opaque_keys.edx.locations import SlashSeparatedCourseKey
|
|
||||||
from xmodule.mako_module import MakoDescriptorSystem
|
|
||||||
from xmodule.error_module import ErrorDescriptor
|
|
||||||
from xmodule.assetstore import AssetMetadata
|
from xmodule.assetstore import AssetMetadata
|
||||||
|
from xmodule.error_module import ErrorDescriptor
|
||||||
|
from xmodule.mako_module import MakoDescriptorSystem
|
||||||
from xmodule.modulestore import ModuleStoreEnum
|
from xmodule.modulestore import ModuleStoreEnum
|
||||||
|
from xmodule.modulestore.draft_and_published import DIRECT_ONLY_CATEGORIES, ModuleStoreDraftAndPublished
|
||||||
|
from xmodule.modulestore.inheritance import InheritanceMixin, own_metadata
|
||||||
from xmodule.modulestore.mongo.draft import DraftModuleStore
|
from xmodule.modulestore.mongo.draft import DraftModuleStore
|
||||||
from xmodule.modulestore.xml import CourseLocationManager
|
from xmodule.modulestore.xml import CourseLocationManager
|
||||||
from xmodule.modulestore.draft_and_published import DIRECT_ONLY_CATEGORIES, ModuleStoreDraftAndPublished
|
from xmodule.x_module import ModuleSystem, XModuleDescriptor, XModuleMixin
|
||||||
|
|
||||||
|
|
||||||
MODULE_DIR = path(__file__).dirname()
|
MODULE_DIR = path(__file__).dirname()
|
||||||
@@ -58,7 +58,7 @@ class TestModuleSystem(ModuleSystem): # pylint: disable=abstract-method
|
|||||||
"""
|
"""
|
||||||
ModuleSystem for testing
|
ModuleSystem for testing
|
||||||
"""
|
"""
|
||||||
@mock.patch('eventtracking.tracker.emit')
|
@patch('eventtracking.tracker.emit')
|
||||||
def __init__(self, mock_emit, **kwargs): # pylint: disable=unused-argument
|
def __init__(self, mock_emit, **kwargs): # pylint: disable=unused-argument
|
||||||
id_manager = CourseLocationManager(kwargs['course_id'])
|
id_manager = CourseLocationManager(kwargs['course_id'])
|
||||||
kwargs.setdefault('id_reader', id_manager)
|
kwargs.setdefault('id_reader', id_manager)
|
||||||
@@ -224,57 +224,152 @@ def map_references(value, field, actual_course_key):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
class BulkAssertionManager(object):
|
class BulkAssertionError(AssertionError):
|
||||||
|
"""
|
||||||
|
An AssertionError that contains many sub-assertions.
|
||||||
|
"""
|
||||||
|
def __init__(self, assertion_errors):
|
||||||
|
self.errors = assertion_errors
|
||||||
|
super(BulkAssertionError, self).__init__("The following assertions were raised:\n{}".format(
|
||||||
|
"\n\n".join(self.errors)
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
class _BulkAssertionManager(object):
|
||||||
"""
|
"""
|
||||||
This provides a facility for making a large number of assertions, and seeing all of
|
This provides a facility for making a large number of assertions, and seeing all of
|
||||||
the failures at once, rather than only seeing single failures.
|
the failures at once, rather than only seeing single failures.
|
||||||
"""
|
"""
|
||||||
def __init__(self, test_case):
|
def __init__(self, test_case):
|
||||||
self._equal_assertions = []
|
self._assertion_errors = []
|
||||||
self._test_case = test_case
|
self._test_case = test_case
|
||||||
|
|
||||||
def run_assertions(self):
|
def log_error(self, formatted_exc):
|
||||||
if len(self._equal_assertions) > 0:
|
"""
|
||||||
raise AssertionError(self._equal_assertions)
|
Record ``formatted_exc`` in the set of exceptions captured by this assertion manager.
|
||||||
|
"""
|
||||||
|
self._assertion_errors.append(formatted_exc)
|
||||||
|
|
||||||
|
def raise_assertion_errors(self):
|
||||||
|
"""
|
||||||
|
Raise a BulkAssertionError containing all of the captured AssertionErrors,
|
||||||
|
if there were any.
|
||||||
|
"""
|
||||||
|
if self._assertion_errors:
|
||||||
|
raise BulkAssertionError(self._assertion_errors)
|
||||||
|
|
||||||
|
|
||||||
class BulkAssertionTest(unittest.TestCase):
|
class BulkAssertionTest(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
This context manager provides a BulkAssertionManager to assert with,
|
This context manager provides a _BulkAssertionManager to assert with,
|
||||||
and then calls `run_assertions` at the end of the block to validate all
|
and then calls `raise_assertion_errors` at the end of the block to validate all
|
||||||
of the assertions.
|
of the assertions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def setUp(self, *args, **kwargs):
|
def setUp(self, *args, **kwargs):
|
||||||
super(BulkAssertionTest, self).setUp(*args, **kwargs)
|
super(BulkAssertionTest, self).setUp(*args, **kwargs)
|
||||||
self._manager = None
|
# Use __ to not pollute the namespace of subclasses with what could be a fairly generic name.
|
||||||
|
self.__manager = None
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def bulk_assertions(self):
|
def bulk_assertions(self):
|
||||||
if self._manager:
|
"""
|
||||||
|
A context manager that will capture all assertion failures made by self.assert*
|
||||||
|
methods within its context, and raise a single combined assertion error at
|
||||||
|
the end of the context.
|
||||||
|
"""
|
||||||
|
if self.__manager:
|
||||||
yield
|
yield
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
self._manager = BulkAssertionManager(self)
|
self.__manager = _BulkAssertionManager(self)
|
||||||
yield
|
yield
|
||||||
finally:
|
except Exception:
|
||||||
self._manager.run_assertions()
|
raise
|
||||||
self._manager = None
|
else:
|
||||||
|
manager = self.__manager
|
||||||
|
self.__manager = None
|
||||||
|
manager.raise_assertion_errors()
|
||||||
|
|
||||||
def assertEqual(self, expected, actual, message=None):
|
@contextmanager
|
||||||
if self._manager is not None:
|
def _capture_assertion_errors(self):
|
||||||
try:
|
"""
|
||||||
super(BulkAssertionTest, self).assertEqual(expected, actual, message)
|
A context manager that captures any AssertionError raised within it,
|
||||||
except Exception as error: # pylint: disable=broad-except
|
and, if within a ``bulk_assertions`` context, records the captured
|
||||||
exc_stack = inspect.stack()[1]
|
assertion to the bulk assertion manager. If not within a ``bulk_assertions``
|
||||||
if message is not None:
|
context, just raises the original exception.
|
||||||
msg = '{} -> {}:{} -> {}'.format(message, exc_stack[1], exc_stack[2], unicode(error))
|
"""
|
||||||
else:
|
try:
|
||||||
msg = '{}:{} -> {}'.format(exc_stack[1], exc_stack[2], unicode(error))
|
# Only wrap the first layer of assert functions by stashing away the manager
|
||||||
self._manager._equal_assertions.append(msg) # pylint: disable=protected-access
|
# before executing the assertion.
|
||||||
|
manager = self.__manager
|
||||||
|
self.__manager = None
|
||||||
|
yield
|
||||||
|
except AssertionError: # pylint: disable=broad-except
|
||||||
|
if manager is not None:
|
||||||
|
# Reconstruct the stack in which the error was thrown (so that the traceback)
|
||||||
|
# isn't cut off at `assertion(*args, **kwargs)`.
|
||||||
|
exc_type, exc_value, exc_tb = sys.exc_info()
|
||||||
|
|
||||||
|
# Count the number of stack frames before you get to a
|
||||||
|
# unittest context (walking up the stack from here).
|
||||||
|
relevant_frames = 0
|
||||||
|
for frame_record in inspect.stack():
|
||||||
|
# This is the same criterion used by unittest to decide if a
|
||||||
|
# stack frame is relevant to exception printing.
|
||||||
|
frame = frame_record[0]
|
||||||
|
if '__unittest' in frame.f_globals:
|
||||||
|
break
|
||||||
|
relevant_frames += 1
|
||||||
|
|
||||||
|
stack_above = traceback.extract_stack()[-relevant_frames:-1]
|
||||||
|
|
||||||
|
stack_below = traceback.extract_tb(exc_tb)
|
||||||
|
formatted_stack = traceback.format_list(stack_above + stack_below)
|
||||||
|
formatted_exc = traceback.format_exception_only(exc_type, exc_value)
|
||||||
|
manager.log_error(
|
||||||
|
"".join(formatted_stack + formatted_exc)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
self.__manager = manager
|
||||||
|
|
||||||
|
def _wrap_assertion(self, assertion):
|
||||||
|
"""
|
||||||
|
Wraps an assert* method to capture an immediate exception,
|
||||||
|
or to generate a new assertion capturing context (in the case of assertRaises
|
||||||
|
and assertRaisesRegexp).
|
||||||
|
"""
|
||||||
|
@wraps(assertion)
|
||||||
|
def assert_(*args, **kwargs):
|
||||||
|
"""
|
||||||
|
Execute a captured assertion, and catch any assertion errors raised.
|
||||||
|
"""
|
||||||
|
context = None
|
||||||
|
|
||||||
|
# Run the assertion, and capture any raised assertionErrors
|
||||||
|
with self._capture_assertion_errors():
|
||||||
|
context = assertion(*args, **kwargs)
|
||||||
|
|
||||||
|
# Handle the assertRaises family of functions by returning
|
||||||
|
# a context manager that surrounds the assertRaises
|
||||||
|
# with our assertion capturing context manager.
|
||||||
|
if context is not None:
|
||||||
|
return nested(self._capture_assertion_errors(), context)
|
||||||
|
|
||||||
|
return assert_
|
||||||
|
|
||||||
|
def __getattribute__(self, name):
|
||||||
|
"""
|
||||||
|
Wrap all assert* methods of this class using self._wrap_assertion,
|
||||||
|
to capture all assertion errors in bulk.
|
||||||
|
"""
|
||||||
|
base_attr = super(BulkAssertionTest, self).__getattribute__(name)
|
||||||
|
if name.startswith('assert'):
|
||||||
|
return self._wrap_assertion(base_attr)
|
||||||
else:
|
else:
|
||||||
super(BulkAssertionTest, self).assertEqual(expected, actual, message)
|
return base_attr
|
||||||
assertEquals = assertEqual
|
|
||||||
|
|
||||||
|
|
||||||
class LazyFormat(object):
|
class LazyFormat(object):
|
||||||
@@ -297,6 +392,12 @@ class LazyFormat(object):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return unicode(self)
|
return unicode(self)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(unicode(self))
|
||||||
|
|
||||||
|
def __getitem__(self, index):
|
||||||
|
return unicode(self)[index]
|
||||||
|
|
||||||
|
|
||||||
class CourseComparisonTest(BulkAssertionTest):
|
class CourseComparisonTest(BulkAssertionTest):
|
||||||
"""
|
"""
|
||||||
@@ -432,6 +533,13 @@ class CourseComparisonTest(BulkAssertionTest):
|
|||||||
for item in actual_items
|
for item in actual_items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Split Mongo and Old-Mongo disagree about what the block_id of courses is, so skip those in
|
||||||
|
# this comparison
|
||||||
|
self.assertItemsEqual(
|
||||||
|
[map_key(item.location) for item in expected_items if item.scope_ids.block_type != 'course'],
|
||||||
|
[key for key in actual_item_map.keys() if key[0] != 'course'],
|
||||||
|
)
|
||||||
|
|
||||||
for expected_item in expected_items:
|
for expected_item in expected_items:
|
||||||
actual_item_location = actual_course_key.make_usage_key(expected_item.category, expected_item.location.block_id)
|
actual_item_location = actual_course_key.make_usage_key(expected_item.category, expected_item.location.block_id)
|
||||||
# split and old mongo use different names for the course root but we don't know which
|
# split and old mongo use different names for the course root but we don't know which
|
||||||
@@ -445,7 +553,10 @@ class CourseComparisonTest(BulkAssertionTest):
|
|||||||
actual_item = actual_item_map.get(map_key(actual_item_location))
|
actual_item = actual_item_map.get(map_key(actual_item_location))
|
||||||
|
|
||||||
# Formatting the message slows down tests of large courses significantly, so only do it if it would be used
|
# Formatting the message slows down tests of large courses significantly, so only do it if it would be used
|
||||||
self.assertIsNotNone(actual_item, LazyFormat(u'cannot find {} in {}', map_key(actual_item_location), actual_item_map))
|
self.assertIn(map_key(actual_item_location), actual_item_map.keys())
|
||||||
|
|
||||||
|
if actual_item is None:
|
||||||
|
continue
|
||||||
|
|
||||||
# compare fields
|
# compare fields
|
||||||
self.assertEqual(expected_item.fields, actual_item.fields)
|
self.assertEqual(expected_item.fields, actual_item.fields)
|
||||||
|
|||||||
@@ -1,77 +1,167 @@
|
|||||||
import ddt
|
import ddt
|
||||||
from xmodule.tests import BulkAssertionTest
|
import itertools
|
||||||
|
from xmodule.tests import BulkAssertionTest, BulkAssertionError
|
||||||
|
|
||||||
|
|
||||||
|
STATIC_PASSING_ASSERTIONS = (
|
||||||
|
('assertTrue', True),
|
||||||
|
('assertFalse', False),
|
||||||
|
('assertIs', 1, 1),
|
||||||
|
('assertEqual', 1, 1),
|
||||||
|
('assertEquals', 1, 1),
|
||||||
|
('assertIsNot', 1, 2),
|
||||||
|
('assertIsNone', None),
|
||||||
|
('assertIsNotNone', 1),
|
||||||
|
('assertIn', 1, (1, 2, 3)),
|
||||||
|
('assertNotIn', 5, (1, 2, 3)),
|
||||||
|
('assertIsInstance', 1, int),
|
||||||
|
('assertNotIsInstance', '1', int),
|
||||||
|
('assertItemsEqual', [1, 2, 3], [3, 2, 1])
|
||||||
|
)
|
||||||
|
|
||||||
|
STATIC_FAILING_ASSERTIONS = (
|
||||||
|
('assertTrue', False),
|
||||||
|
('assertFalse', True),
|
||||||
|
('assertIs', 1, 2),
|
||||||
|
('assertEqual', 1, 2),
|
||||||
|
('assertEquals', 1, 2),
|
||||||
|
('assertIsNot', 1, 1),
|
||||||
|
('assertIsNone', 1),
|
||||||
|
('assertIsNotNone', None),
|
||||||
|
('assertIn', 5, (1, 2, 3)),
|
||||||
|
('assertNotIn', 1, (1, 2, 3)),
|
||||||
|
('assertIsInstance', '1', int),
|
||||||
|
('assertNotIsInstance', 1, int),
|
||||||
|
('assertItemsEqual', [1, 1, 1], [1, 1])
|
||||||
|
)
|
||||||
|
|
||||||
|
CONTEXT_PASSING_ASSERTIONS = (
|
||||||
|
('assertRaises', KeyError, {}.__getitem__, '1'),
|
||||||
|
('assertRaisesRegexp', KeyError, "1", {}.__getitem__, '1'),
|
||||||
|
)
|
||||||
|
|
||||||
|
CONTEXT_FAILING_ASSERTIONS = (
|
||||||
|
('assertRaises', ValueError, lambda: None),
|
||||||
|
('assertRaisesRegexp', KeyError, "2", {}.__getitem__, '1'),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
@ddt.ddt
|
||||||
class TestBulkAssertionTestCase(BulkAssertionTest):
|
class TestBulkAssertionTestCase(BulkAssertionTest):
|
||||||
|
|
||||||
@ddt.data(
|
# We have to use assertion methods from the base UnitTest class,
|
||||||
('assertTrue', True),
|
# so we make a number of super calls that skip BulkAssertionTest.
|
||||||
('assertFalse', False),
|
|
||||||
('assertIs', 1, 1),
|
# pylint: disable=bad-super-call
|
||||||
('assertIsNot', 1, 2),
|
|
||||||
('assertIsNone', None),
|
def _run_assertion(self, assertion_tuple):
|
||||||
('assertIsNotNone', 1),
|
"""
|
||||||
('assertIn', 1, (1, 2, 3)),
|
Run the supplied tuple of (assertion, *args) as a method on this class.
|
||||||
('assertNotIn', 5, (1, 2, 3)),
|
"""
|
||||||
('assertIsInstance', 1, int),
|
assertion, args = assertion_tuple[0], assertion_tuple[1:]
|
||||||
('assertNotIsInstance', '1', int),
|
|
||||||
('assertRaises', KeyError, {}.__getitem__, '1'),
|
|
||||||
)
|
|
||||||
@ddt.unpack
|
|
||||||
def test_passing_asserts_passthrough(self, assertion, *args):
|
|
||||||
getattr(self, assertion)(*args)
|
getattr(self, assertion)(*args)
|
||||||
|
|
||||||
@ddt.data(
|
def _raw_assert(self, assertion_name, *args, **kwargs):
|
||||||
('assertTrue', False),
|
"""
|
||||||
('assertFalse', True),
|
Run an un-modified assertion.
|
||||||
('assertIs', 1, 2),
|
"""
|
||||||
('assertIsNot', 1, 1),
|
# Use super(BulkAssertionTest) to make sure we get un-adulturated assertions
|
||||||
('assertIsNone', 1),
|
return getattr(super(BulkAssertionTest, self), 'assert' + assertion_name)(*args, **kwargs)
|
||||||
('assertIsNotNone', None),
|
|
||||||
('assertIn', 5, (1, 2, 3)),
|
@ddt.data(*(STATIC_PASSING_ASSERTIONS + CONTEXT_PASSING_ASSERTIONS))
|
||||||
('assertNotIn', 1, (1, 2, 3)),
|
def test_passing_asserts_passthrough(self, assertion_tuple):
|
||||||
('assertIsInstance', '1', int),
|
self._run_assertion(assertion_tuple)
|
||||||
('assertNotIsInstance', 1, int),
|
|
||||||
('assertRaises', ValueError, lambda: None),
|
@ddt.data(*(STATIC_FAILING_ASSERTIONS + CONTEXT_FAILING_ASSERTIONS))
|
||||||
)
|
def test_failing_asserts_passthrough(self, assertion_tuple):
|
||||||
|
with self._raw_assert('Raises', AssertionError) as context:
|
||||||
|
self._run_assertion(assertion_tuple)
|
||||||
|
|
||||||
|
self._raw_assert('NotIsInstance', context.exception, BulkAssertionError)
|
||||||
|
|
||||||
|
@ddt.data(*CONTEXT_PASSING_ASSERTIONS)
|
||||||
@ddt.unpack
|
@ddt.unpack
|
||||||
def test_failing_asserts_passthrough(self, assertion, *args):
|
def test_passing_context_assertion_passthrough(self, assertion, *args):
|
||||||
# Use super(BulkAssertionTest) to make sure we get un-adulturated assertions
|
assertion_args = []
|
||||||
with super(BulkAssertionTest, self).assertRaises(AssertionError):
|
args = list(args)
|
||||||
getattr(self, assertion)(*args)
|
|
||||||
|
|
||||||
def test_no_bulk_assert_equals(self):
|
exception = args.pop(0)
|
||||||
# Use super(BulkAssertionTest) to make sure we get un-adulturated assertions
|
|
||||||
with super(BulkAssertionTest, self).assertRaises(AssertionError):
|
|
||||||
self.assertEquals(1, 2)
|
|
||||||
|
|
||||||
@ddt.data(
|
while not callable(args[0]):
|
||||||
'assertEqual', 'assertEquals'
|
assertion_args.append(args.pop(0))
|
||||||
)
|
|
||||||
def test_bulk_assert_equals(self, asserterFn):
|
function = args.pop(0)
|
||||||
asserter = getattr(self, asserterFn)
|
|
||||||
|
with getattr(self, assertion)(exception, *assertion_args):
|
||||||
|
function(*args)
|
||||||
|
|
||||||
|
@ddt.data(*CONTEXT_FAILING_ASSERTIONS)
|
||||||
|
@ddt.unpack
|
||||||
|
def test_failing_context_assertion_passthrough(self, assertion, *args):
|
||||||
|
assertion_args = []
|
||||||
|
args = list(args)
|
||||||
|
|
||||||
|
exception = args.pop(0)
|
||||||
|
|
||||||
|
while not callable(args[0]):
|
||||||
|
assertion_args.append(args.pop(0))
|
||||||
|
|
||||||
|
function = args.pop(0)
|
||||||
|
|
||||||
|
with self._raw_assert('Raises', AssertionError) as context:
|
||||||
|
with getattr(self, assertion)(exception, *assertion_args):
|
||||||
|
function(*args)
|
||||||
|
|
||||||
|
self._raw_assert('NotIsInstance', context.exception, BulkAssertionError)
|
||||||
|
|
||||||
|
@ddt.data(*list(itertools.product(
|
||||||
|
CONTEXT_PASSING_ASSERTIONS,
|
||||||
|
CONTEXT_FAILING_ASSERTIONS,
|
||||||
|
CONTEXT_FAILING_ASSERTIONS
|
||||||
|
)))
|
||||||
|
@ddt.unpack
|
||||||
|
def test_bulk_assert(self, passing_assertion, failing_assertion1, failing_assertion2):
|
||||||
contextmanager = self.bulk_assertions()
|
contextmanager = self.bulk_assertions()
|
||||||
|
|
||||||
contextmanager.__enter__()
|
contextmanager.__enter__()
|
||||||
super(BulkAssertionTest, self).assertIsNotNone(self._manager)
|
self._run_assertion(passing_assertion)
|
||||||
asserter(1, 2)
|
self._run_assertion(failing_assertion1)
|
||||||
asserter(3, 4)
|
self._run_assertion(failing_assertion2)
|
||||||
|
|
||||||
# Use super(BulkAssertionTest) to make sure we get un-adulturated assertions
|
with self._raw_assert('Raises', BulkAssertionError) as context:
|
||||||
with super(BulkAssertionTest, self).assertRaises(AssertionError):
|
|
||||||
contextmanager.__exit__(None, None, None)
|
contextmanager.__exit__(None, None, None)
|
||||||
|
|
||||||
@ddt.data(
|
self._raw_assert('Equals', len(context.exception.errors), 2)
|
||||||
'assertEqual', 'assertEquals'
|
|
||||||
)
|
|
||||||
def test_bulk_assert_closed(self, asserterFn):
|
|
||||||
asserter = getattr(self, asserterFn)
|
|
||||||
|
|
||||||
with self.bulk_assertions():
|
@ddt.data(*list(itertools.product(
|
||||||
asserter(1, 1)
|
CONTEXT_FAILING_ASSERTIONS
|
||||||
asserter(2, 2)
|
)))
|
||||||
|
@ddt.unpack
|
||||||
|
def test_nested_bulk_asserts(self, failing_assertion):
|
||||||
|
with self._raw_assert('Raises', BulkAssertionError) as context:
|
||||||
|
with self.bulk_assertions():
|
||||||
|
self._run_assertion(failing_assertion)
|
||||||
|
with self.bulk_assertions():
|
||||||
|
self._run_assertion(failing_assertion)
|
||||||
|
self._run_assertion(failing_assertion)
|
||||||
|
|
||||||
# Use super(BulkAssertionTest) to make sure we get un-adulturated assertions
|
self._raw_assert('Equal', len(context.exception.errors), 3)
|
||||||
with super(BulkAssertionTest, self).assertRaises(AssertionError):
|
|
||||||
asserter(1, 2)
|
@ddt.data(*list(itertools.product(
|
||||||
|
CONTEXT_PASSING_ASSERTIONS,
|
||||||
|
CONTEXT_FAILING_ASSERTIONS,
|
||||||
|
CONTEXT_FAILING_ASSERTIONS
|
||||||
|
)))
|
||||||
|
@ddt.unpack
|
||||||
|
def test_bulk_assert_closed(self, passing_assertion, failing_assertion1, failing_assertion2):
|
||||||
|
with self._raw_assert('Raises', BulkAssertionError) as context:
|
||||||
|
with self.bulk_assertions():
|
||||||
|
self._run_assertion(passing_assertion)
|
||||||
|
self._run_assertion(failing_assertion1)
|
||||||
|
|
||||||
|
self._raw_assert('Equals', len(context.exception.errors), 1)
|
||||||
|
|
||||||
|
with self._raw_assert('Raises', AssertionError) as context:
|
||||||
|
self._run_assertion(failing_assertion2)
|
||||||
|
|
||||||
|
self._raw_assert('NotIsInstance', context.exception, BulkAssertionError)
|
||||||
|
|||||||
Reference in New Issue
Block a user