From 72af501f32378e84af6f5407cab4a79d7ec453ac Mon Sep 17 00:00:00 2001 From: Michael Foord Date: Sat, 21 Apr 2012 01:44:18 +0100 Subject: Exceptions in iterable side_effect will be raised --- docs/changelog.txt | 2 ++ docs/examples.txt | 5 +++++ docs/mock.txt | 19 ++++++++++++++++++- mock.py | 9 +++++++-- tests/testmock.py | 10 ++++++++++ 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 8b65457..ad16637 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -11,6 +11,8 @@ CHANGELOG * `PropertyMock` attributes are now standard `MagicMocks` * `create_autospec` works with attributes present in results of `dir` that can't be fetched from the object's class. Contributed by Konstantine Rybnikov +* Any exceptions in an iterable `side_effect` will be raised instead of + returned 2012/03/25 Version 1.0.0 alpha 1 diff --git a/docs/examples.txt b/docs/examples.txt index d35dd45..d6a96fb 100644 --- a/docs/examples.txt +++ b/docs/examples.txt @@ -498,6 +498,11 @@ children of a `CopyingMock` will also have the type `CopyingMock`. Multiple calls with different effects ===================================== +.. note:: + + In mock 1.0 the handling of iterable `side_effect` was changed. Any + exceptions in the iterable will be raised instead of returned. + Handling code that needs to behave differently on subsequent calls during the test can be tricky. For example you may have a function that needs to raise an exception the first time it is called but returns a response on the second diff --git a/docs/mock.txt b/docs/mock.txt index e5dcd60..58712b2 100644 --- a/docs/mock.txt +++ b/docs/mock.txt @@ -61,7 +61,8 @@ the `new_callable` argument to `patch`. this case the exception will be raised when the mock is called. If `side_effect` is an iterable then each call to the mock will return - the next value from the iterable. + the next value from the iterable. If any of the members of the iterable + are exceptions they will be raised instead of returned. A `side_effect` can be cleared by setting it to `None`. @@ -728,6 +729,22 @@ a `StopIteration` is raised): ... StopIteration +If any members of the iterable are exceptions they will be raised instead of +returned: + +.. doctest:: + + >>> iterable = (33, ValueError, 66) + >>> m = MagicMock(side_effect=iterable) + >>> m() + 33 + >>> m() + Traceback (most recent call last): + ... + ValueError + >>> m() + 66 + .. _deleting-attributes: diff --git a/mock.py b/mock.py index 6e9c18a..16f0fc8 100644 --- a/mock.py +++ b/mock.py @@ -981,8 +981,12 @@ class CallableMixin(Base): if _is_exception(effect): raise effect + ret_val = DEFAULT if not _callable(effect): - return next(effect) + result = next(effect) + if _is_exception(result): + raise result + return result ret_val = effect(*args, **kwargs) if ret_val is DEFAULT: @@ -1026,7 +1030,8 @@ class Mock(CallableMixin, NonCallableMock): this case the exception will be raised when the mock is called. If `side_effect` is an iterable then each call to the mock will return - the next value from the iterable. + the next value from the iterable. If any of the members of the iterable + are exceptions they will be raised instead of returned. * `return_value`: The value returned when the mock is called. By default this is a new Mock (created on first access). See the diff --git a/tests/testmock.py b/tests/testmock.py index 1f3bdf9..f3ceea9 100644 --- a/tests/testmock.py +++ b/tests/testmock.py @@ -959,6 +959,16 @@ class MockTest(unittest2.TestCase): self.assertIs(mock.side_effect, this_iter) + def test_side_effect_iterator_exceptions(self): + for Klass in Mock, MagicMock: + iterable = (ValueError, 3, KeyError, 6) + m = Klass(side_effect=iterable) + self.assertRaises(ValueError, m) + self.assertEqual(m(), 3) + self.assertRaises(KeyError, m) + self.assertEqual(m(), 6) + + def test_assert_has_calls_any_order(self): mock = Mock() mock(1, 2) -- cgit v1.2.1