Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any difference between using mock.patch.object with wraps vs side_effect?

What is the difference between the following two tests? (if any)

** in python 3.10

import unittest
from unittest.mock import Mock, patch

class Potato(object):
    def spam(self, n):
        return self.foo(n=n)

    def foo(self, n):
        return self.bar(n)

    def bar(self, n):
        return n + 2

class PotatoTest(unittest.TestCase):
    def test_side_effect(self):
        spud = Potato()
        with patch.object(spud, 'foo', side_effect=spud.foo) as mock_foo:
            forty_two = spud.spam(n=40)
            mock_foo.assert_called_once_with(n=40)
        self.assertEqual(forty_two, 42)

    def test_wraps(self):
        spud = Potato()
        with patch.object(spud, 'foo', wraps=spud.foo) as mock_foo:
            forty_two = spud.spam(n=40)
            mock_foo.assert_called_once_with(n=40)
        self.assertEqual(forty_two, 42)

One uses side_effect to preserve the original method while the other uses wraps to effectively do the same thing (or at least as far as I can tell).

like image 829
Marcel Wilson Avatar asked Jul 02 '26 16:07

Marcel Wilson


1 Answers

a bit late to the party, here's what I found in python source code.

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method

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

            if result is not DEFAULT:
                return result

        if self._mock_return_value is not DEFAULT:
            return self.return_value

        if self._mock_wraps is not None:
            return self._mock_wraps(*args, **kwargs)

        return self.return_value

As can be seen from above, side_effect could just be an exception or an iterator that returns an exception. Where as wraps would just simply pass through.

IMO, use side_effect when you want to raise exceptions, use "wraps" when you're "spying" on the method.

like image 81
rabbit.aaron Avatar answered Jul 05 '26 06:07

rabbit.aaron



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!