Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions Lib/unittest/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -1005,28 +1005,27 @@ def _mock_call(_mock_self, *args, **kwargs):
break
seen.add(_new_parent_id)

ret_val = DEFAULT
effect = self.side_effect
if effect is not None:
if _is_exception(effect):
raise effect

if not _callable(effect):
elif not _callable(effect):
result = next(effect)
if _is_exception(result):
raise result
if result is DEFAULT:
result = self.return_value
else:
result = effect(*args, **kwargs)

if result is not DEFAULT:
return result

ret_val = effect(*args, **kwargs)
if self._mock_return_value is not DEFAULT:
return self.return_value

if (self._mock_wraps is not None and
self._mock_return_value is DEFAULT):
if self._mock_wraps is not None:
return self._mock_wraps(*args, **kwargs)
if ret_val is DEFAULT:
ret_val = self.return_value
return ret_val

return self.return_value



Expand Down
122 changes: 122 additions & 0 deletions Lib/unittest/test/testmock/testmock.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,16 @@ def test_wraps_calls(self):
real.assert_called_with(1, 2, fish=3)


def test_wraps_prevents_automatic_creation_of_mocks(self):
class Real(object):
pass

real = Real()
mock = Mock(wraps=real)

self.assertRaises(AttributeError, lambda: mock.new_attr())


def test_wraps_call_with_nondefault_return_value(self):
real = Mock()

Expand All @@ -575,6 +585,118 @@ class Real(object):
self.assertEqual(result, Real.attribute.frog())


def test_customize_wrapped_object_with_side_effect_iterable_with_default(self):
class Real(object):
def method(self):
return sentinel.ORIGINAL_VALUE

real = Real()
mock = Mock(wraps=real)
mock.method.side_effect = [sentinel.VALUE1, DEFAULT]

self.assertEqual(mock.method(), sentinel.VALUE1)
self.assertEqual(mock.method(), sentinel.ORIGINAL_VALUE)
self.assertRaises(StopIteration, mock.method)


def test_customize_wrapped_object_with_side_effect_iterable(self):
class Real(object):
def method(self):
raise NotImplementedError()

real = Real()
mock = Mock(wraps=real)
mock.method.side_effect = [sentinel.VALUE1, sentinel.VALUE2]

self.assertEqual(mock.method(), sentinel.VALUE1)
self.assertEqual(mock.method(), sentinel.VALUE2)
self.assertRaises(StopIteration, mock.method)


def test_customize_wrapped_object_with_side_effect_exception(self):
class Real(object):
def method(self):
raise NotImplementedError()

real = Real()
mock = Mock(wraps=real)
mock.method.side_effect = RuntimeError

self.assertRaises(RuntimeError, mock.method)


def test_customize_wrapped_object_with_side_effect_function(self):
class Real(object):
def method(self):
raise NotImplementedError()

def side_effect():
return sentinel.VALUE

real = Real()
mock = Mock(wraps=real)
mock.method.side_effect = side_effect

self.assertEqual(mock.method(), sentinel.VALUE)


def test_customize_wrapped_object_with_return_value(self):
class Real(object):
def method(self):
raise NotImplementedError()

real = Real()
mock = Mock(wraps=real)
mock.method.return_value = sentinel.VALUE

self.assertEqual(mock.method(), sentinel.VALUE)


def test_customize_wrapped_object_with_return_value_and_side_effect(self):
# side_effect should always take precedence over return_value.
class Real(object):
def method(self):
raise NotImplementedError()

real = Real()
mock = Mock(wraps=real)
mock.method.side_effect = [sentinel.VALUE1, sentinel.VALUE2]
mock.method.return_value = sentinel.WRONG_VALUE

self.assertEqual(mock.method(), sentinel.VALUE1)
self.assertEqual(mock.method(), sentinel.VALUE2)
self.assertRaises(StopIteration, mock.method)


def test_customize_wrapped_object_with_return_value_and_side_effect2(self):
# side_effect can return DEFAULT to default to return_value
class Real(object):
def method(self):
raise NotImplementedError()

real = Real()
mock = Mock(wraps=real)
mock.method.side_effect = lambda: DEFAULT
mock.method.return_value = sentinel.VALUE

self.assertEqual(mock.method(), sentinel.VALUE)


def test_customize_wrapped_object_with_return_value_and_side_effect_default(self):
class Real(object):
def method(self):
raise NotImplementedError()

real = Real()
mock = Mock(wraps=real)
mock.method.side_effect = [sentinel.VALUE1, DEFAULT]
mock.method.return_value = sentinel.RETURN

self.assertEqual(mock.method(), sentinel.VALUE1)
self.assertEqual(mock.method(), sentinel.RETURN)
self.assertRaises(StopIteration, mock.method)


def test_exceptional_side_effect(self):
mock = Mock(side_effect=AttributeError)
self.assertRaises(AttributeError, mock)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
When a :class:`Mock` instance was used to wrap an object, if `side_effect`
is used in one of the mocks of it methods, don't call the original
implementation and return the result of using the side effect the same way
that it is done with return_value.