According to the unittest.mock documentation for side_effect:

If you pass in an iterable, it is used to retrieve an iterator which must yield a value on every call. This value can either be an exception instance to be raised, or a value to be returned from the call to the mock (DEFAULT handling is identical to the function case).

Therefore, your socket.create_connection mock will return the function oddConnect for the first two calls, then return the Mock object for the last call. From what I understand, you want to mock create_connection object to actually call those functions as side effects rather than returning them.

I find this behavior rather odd, since you'd expect side_effect, to mean side_effect in every case, not return_value. I suppose the reason this is so lies in the fact that the value of the return_value property must be interpreted as-is. For instance, if your Mock had return_value=[1, 2, 3], would your Mock return [1, 2, 3] for every call, or would it return 1 for the first call?

Solution

Fortunately, there is a solution to this problem. According to the docs, if you pass a single function to side_effect, then that function will be called (not returned) every time the mock is called.

If you pass in a function it will be called with same arguments as the mock and unless the function returns the DEFAULT singleton the call to the mock will then return whatever the function returns. If the function returns DEFAULT then the mock will return its normal value (from the return_value).

Therefore, in order to achieve the desired effect, your side_effect function must do something different every time it is called. You can easily achieve this with a counter and some conditional logic in your function. Note that in order for this to work, your counter must exist outside the scope of the function, so the counter isn't reset when the function exits.

import mock
import socket

# You may wish to encapsulate times_called and oddConnect in a class
times_called = 0
def oddConnect():
  times_called += 1
  # We only do something special the first two times oddConnect is called
  if times_called <= 2:
    result = mock.MagicMock()  # this is where the return value would go
    raise socket.error  # I want it assigned but also this raised  

socket.create_connection = mock(spec=socket.create_connection,
  side_effect=oddConnect)
# what I want: call my function twice, and on the third time return normally
# what I get: two function objects returned and then the normal return

for _ in xrange(3):
  result = None
  try:
    # this is the context in which I want the oddConnect function call
    # to be called (not above when creating the list)
    result = socket.create_connection()
  except socket.error:
    if result is not None:
      # I should get here twice
      result.close()
      result = None
  if result is not None:
    # happy days we have a connection
    # I should get here the third time
    pass
Answer from caleb531 on Stack Overflow
🌐
Python
docs.python.org › 3 › library › unittest.mock.html
unittest.mock — mock object library
A side_effect can be cleared by setting it to None. return_value: The value returned when the mock is called. By default this is a new Mock (created on first access).
Top answer
1 of 2
13

According to the unittest.mock documentation for side_effect:

If you pass in an iterable, it is used to retrieve an iterator which must yield a value on every call. This value can either be an exception instance to be raised, or a value to be returned from the call to the mock (DEFAULT handling is identical to the function case).

Therefore, your socket.create_connection mock will return the function oddConnect for the first two calls, then return the Mock object for the last call. From what I understand, you want to mock create_connection object to actually call those functions as side effects rather than returning them.

I find this behavior rather odd, since you'd expect side_effect, to mean side_effect in every case, not return_value. I suppose the reason this is so lies in the fact that the value of the return_value property must be interpreted as-is. For instance, if your Mock had return_value=[1, 2, 3], would your Mock return [1, 2, 3] for every call, or would it return 1 for the first call?

Solution

Fortunately, there is a solution to this problem. According to the docs, if you pass a single function to side_effect, then that function will be called (not returned) every time the mock is called.

If you pass in a function it will be called with same arguments as the mock and unless the function returns the DEFAULT singleton the call to the mock will then return whatever the function returns. If the function returns DEFAULT then the mock will return its normal value (from the return_value).

Therefore, in order to achieve the desired effect, your side_effect function must do something different every time it is called. You can easily achieve this with a counter and some conditional logic in your function. Note that in order for this to work, your counter must exist outside the scope of the function, so the counter isn't reset when the function exits.

import mock
import socket

# You may wish to encapsulate times_called and oddConnect in a class
times_called = 0
def oddConnect():
  times_called += 1
  # We only do something special the first two times oddConnect is called
  if times_called <= 2:
    result = mock.MagicMock()  # this is where the return value would go
    raise socket.error  # I want it assigned but also this raised  

socket.create_connection = mock(spec=socket.create_connection,
  side_effect=oddConnect)
# what I want: call my function twice, and on the third time return normally
# what I get: two function objects returned and then the normal return

for _ in xrange(3):
  result = None
  try:
    # this is the context in which I want the oddConnect function call
    # to be called (not above when creating the list)
    result = socket.create_connection()
  except socket.error:
    if result is not None:
      # I should get here twice
      result.close()
      result = None
  if result is not None:
    # happy days we have a connection
    # I should get here the third time
    pass
2 of 2
2

I also encountered the problem of wanting a side effect to occur for only some items in a list of values.

In my case, I wanted to call a method from freezegun the third time my mocked method was called. These answers were really helpful for me; I ended up writing up a fairly general wrapper class, which I thought I'd share here:

class DelayedSideEffect:
    """
    If DelayedSideEffect.side_effect is assigned to a mock.side_effect, allows you to
    delay the first call of callback until after a certain number of iterations.
    """
    def __init__(self, callback, delay_until_call_num: int, return_value=DEFAULT):
        self.times_called = 0
        self.delay_until_call_num = delay_until_call_num
        self.callback = callback
        self.return_value = return_value

    def side_effect(self, *args, **kwargs):
        self.times_called += 1
        if self.times_called >= self.delay_until_call_num:
            self.callback()
        return self.return_value

To then return "my_default_return_value" without calling the lambda function on the first three calls:

with freeze_time(datetime.now()) as freezer:
    se = DelayedSideEffect(callback=lambda: freezer.move_to(the_future), 3)
    my_mock = MagicMock(return_value="my_default_return_value", side_effect=se)
Discussions

Proposal to Modify MagicMock.side_effect for Better Function Mocking in Unit Tests
Over the last few days, I’ve been tackling a problem related to mocking a function that accepts parameters. More specifically, I’ve been trying to test the following logic: def my_function(df) -> pd.DataFrame: return… More on discuss.python.org
🌐 discuss.python.org
2
0
February 2, 2024
unit testing - Python - Mock requests with side_effect - Stack Overflow
I'm trying to mock out the method requests.get() of the module requests and set the attribute side_effect of the obtained instance of the Mock class. I would like to associate a different status_co... More on stackoverflow.com
🌐 stackoverflow.com
python side_effect - mocking behavior of a method - Stack Overflow
In the mock, I want a certain function to return a new value in the test. This is how i did it. Class MyClass: my_var = None def foo(self, var1): return somevalue ... More on stackoverflow.com
🌐 stackoverflow.com
Feat: unittest.Mock.side_effect fails on improper usage - Ideas - Discussions on Python.org
What’s the problem this feature will solve? Mock.side_effect is tricky to use properly. Problem cases include: setting the value to an array of length less than two, in which case return_value is more readable and debuggable setting the value to an array of length n where the value doesn’t ... More on discuss.python.org
🌐 discuss.python.org
2
August 4, 2023
People also ask

What is a side effect in Python?
A side effect in Python is any change that a function makes to the state of the program or to the function's own state, apart from the value it returns. Side effects can include altering global or static variables, modifying the original object, producing console output, or writing to a file or database.
🌐
docs.kanaries.net
docs.kanaries.net › topics › Python › side-effect-in-python
Side_effect in Python - What It Is And How to Use? – Kanaries
Why should you avoid side effects in Python?
Side effects in Python, while not always harmful, can introduce bugs that are difficult to trace and fix. They can make your code unpredictable and hard to reason about. By avoiding side effects, you make your code more stable, predictable, and easier to test.
🌐
docs.kanaries.net
docs.kanaries.net › topics › Python › side-effect-in-python
Side_effect in Python - What It Is And How to Use? – Kanaries
What is a pure function in Python?
A pure function in Python is a function that always produces the same output for the same input and has no side effects. Pure functions are self-contained, making them predictable and easy to test.
🌐
docs.kanaries.net
docs.kanaries.net › topics › Python › side-effect-in-python
Side_effect in Python - What It Is And How to Use? – Kanaries
🌐
Tobydevlin
tobydevlin.com › blog › magicmock-and-side_effect-tricks
MagicMock and side_effect tricks · tobydevlin.com - A personal blog for AI, Data and Platforms.
May 11, 2026 - If you want the mock to return different responses on subsequent calls, you can use the side_effect feature. Setting side_effect to a list, like [None, (1, 2, 3, 4)], will make the mock return None on the first call, and a tuple (1, 2, 3, 4) ...
🌐
Real Python
realpython.com › python-mock-library
Understanding the Python Mock Object Library – Real Python
May 29, 2026 - As you’ve seen in the previous section, you can set .side_effect and .return_value directly on the Mock instance itself after initialization. Some other attributes, such as the name of your Mock, you’d primarily set when initializing the object, like shown above. If you try to set the .name of the Mock on the instance, you’ll get a different result than what you might expect: ... >>> mock = Mock() >>> mock.name = "Real Python Mock" >>> mock <Mock id='4339891024'> >>> mock.name 'Real Python Mock'
🌐
Python
docs.python.org › 3 › library › unittest.mock-examples.html
unittest.mock — getting started
This could then cause problems ... functionality. If you provide a side_effect function for a mock then side_effect will be called with the same args as the mock....
🌐
Opensource.com
opensource.com › article › 23 › 4 › using-mocks-python
Using mocks in Python | Opensource.com
April 1, 2023 - One of the things that can be assigned to side_effect is an iterable, such as a sequence or a generator. This is a powerful feature. It allows controlling each call's return value, with little code. different_things = mock.MagicMock() different_things.side_effect = [1, 2, 3] print(different_things()) print(different_things()) print(different_things())
Find elsewhere
🌐
AskPython
askpython.com › python › built-in-methods › mocking-in-python-unittestmock
Mocking in Python Using Unittest.mock - AskPython
February 2, 2023 - It shall be noted, that the Side Effect has been set after the declaration of the Mock() object. Hence, a Side Effect for a Mock() object can be set anywhere in the code. In the above code, a kv variable is an iterable dictionary. mock2 uses ...
🌐
Pytest with Eric
pytest-with-eric.com › mocking › pytest-mock-multiple-return-values
How To Return Multiple Values From Pytest Mock (Practical Guide) | Pytest with Eric
March 23, 2026 - This guide will walk you through the intricacies of achieving it with Python’s Mock library. We’ll discuss how to return single and multiple values using different methods and adding a dynamic aspect to it. Not only this, but we will delve further into side_effect method, how it is used, and its side effect on your code.
🌐
Kanaries
docs.kanaries.net › topics › Python › side-effect-in-python
Side_effect in Python - What It Is And How to Use? – Kanaries
August 17, 2023 - In this example, add_element is a function that appends an element to a list, causing a side effect. But when we replace add_element with a mock object, it simulates the function without the side effect. This is an example of using mock objects in Python to control side effects.
🌐
Thedmitry
thedmitry.pw › blog › 2020 › 12 › mocks-side-effect
Mock's return_value & side effect - Dmitry's website
December 9, 2020 - Mock's side_effect parameter allows to change the behavior of the mock. It accepts three types of values and changes its behavior accordingly. ... >>> m.simulate_fail.side_effect = ValueError('Whoops...') >>> m.simulate_fail() Traceback (most recent call last): [...] File ".../lib/python3....
🌐
Medium
yeraydiazdiaz.medium.com › what-the-mock-6a71db997832
What the mock? — A cheatsheet for mocking in Python | by Yeray Diaz | Medium
August 19, 2019 - Assign it directly, like you’d do with any Python object. Use the configure_mock method on an instance. Or pass keyword arguments to the Mock class on creation. To override calls to the mock you’ll need to configure its return_value property, also available as a keyword argument in the Mock initializer. The Mock will always return the same value on all calls, this, again, can also be configured by using the side_effect attribute:
🌐
Bright Yellow
ines-panker.com › 2020 › 06 › 01 › python-mock.html
Cheat Sheet of Python Mock by Ines Panker
June 1, 2020 - We tie the mock function to the real function. When the real function changes we need to manually update the test function too. Use return_value when you just want to set what gets returned. Use side_effect when you need different returns per call, exceptions, or custom logic.
🌐
Python.org
discuss.python.org › python help
Proposal to Modify MagicMock.side_effect for Better Function Mocking in Unit Tests - Python Help - Discussions on Python.org
February 2, 2024 - Over the last few days, I’ve been tackling a problem related to mocking a function that accepts parameters. More specifically, I’ve been trying to test the following logic: def my_function(df) -> pd.DataFrame: return ( df.groupby(self.groupby_columns)[ [column_a, column_b] ] .apply(my_function_that_call_external_api) .reset_index() ) def my_function_that_call_external_api(imput_df: pd.DataFrameGroupBy) -> pd.DataFrame:...
Top answer
1 of 2
2

Possible solution with module unittest (not pytest)

I have written this answer before @baguette added the code of its function func1(), so I have created a file called my_file_01.py which contains my production function func1():

import requests

def func1():
    response1 = 'empty1'
    response2 = 'empty2'
    r = requests.get('http://www.someurl.com')
    if r.status_code == 200:
        response1 = r.json()
    r = requests.get('http://www.some_other_url.com')
    if r.status_code == 500:
        response2 = r.json()
    return [response1, response2]

As you can see func1() calls requests.get() two times and checks the status code of responses.

I have inserted the test code in a different file with the following content:

import unittest
from unittest import mock
from my_file_01 import func1

def request_resp1(url):
    response_mock = mock.Mock()
    response_mock.status_code = 200
    response_mock.json.return_value = {'key1': 'value1'}
    # the function return an instance of class Mock
    return response_mock

def request_resp2(url):
    response_mock = mock.Mock()
    response_mock.status_code = 500
    response_mock.json.return_value = "Failed"
    # the function return an instance of class Mock
    return response_mock

class TestFunc1(unittest.TestCase):
    @mock.patch("my_file_01.requests")
    def test_func1(self, mock_requests):
        print("test func1()")
        mock_requests.get.side_effect = [request_resp1(""), request_resp2("")]
        [response1, response2] = func1()
        print("response1 = " + str(response1))
        print("response2 = " + str(response2))

if __name__ == "__main__":
    unittest.main()

The test file defines the test class TestFunc1 which contains the test method test_func1().

Furthermore the file defines 2 functions called request_resp1() and request_resp2(). These functions are used to define different response values when it is called the method requests.get() by the code of func1(); to be more accurate:

  • the first call to requests.get() assigns to variable r the Mock object with status_code = 200 so it simulates a success;
  • the second call to requests.get() assigns to variable r the Mock object with status_code = 500 so it simulates a failure.

If you try to execute the test code you can see that func1() return different values for the 2 different status_codes of the response. The output of the execution is composed by the 3 print() instructions present in test_func1() and is the followed:

test func1()
response1 = {'key1': 'value1'}
response2 = Failed

Useful links

  • For detail about side_effect attribute see its documentation.

  • This is an other example with side_effect

  • request is a Python module and this is a minimal documentation about it.

2 of 2
0

Based on the solution from @frankfalse, the two mocking functions can be replaced by a class.

class MockResponse:
    def __init__(self, json_data, status_code=requests.codes.ok):
        self.json_data = json_data
        self.status_code = status_code

    def json(self):
        return self.json_data

With the previous class the file contained the test code of @frankfalse becomes:

import unittest
from unittest import mock
from my_file_01 import func1
import requests

class MockResponse:
    def __init__(self, json_data, status_code=requests.codes.ok):
        self.json_data = json_data
        self.status_code = status_code

    def json(self):
        return self.json_data

class TestFunc1(unittest.TestCase):
    @mock.patch("my_file_01.requests")
    def test_func1(self, mock_requests):
        print("test func1()")
        mock_requests.get.side_effect = [MockResponse({'key1': 'value1'}), MockResponse('Failed', 500)]
        [response1, response2] = func1()
        print("response1 = " + str(response1))
        print("response2 = " + str(response2))

The differences are:

  • the mocking functions request_resp1() and request_resp2() can be removed
  • it is necessary to add: import requests for the presence of the assignment status_code=requests.codes.ok in the __init__() method
  • the instruction for the definition of side_effect becomes:
    mock_requests.get.side_effect = [MockResponse({'key1': 'value1'}), MockResponse('error', 500)]

Because ith has been created the class MockResponse, the class Mock of the module unittest.mock is not used.

Top answer
1 of 2
17

There are a few issues here.

  1. The arguments you're passing to the @patch decorator aren't quite right. The target should be specified as a single argument:

    @patch('MyClass.foo')
    
  2. Your decorated test function will need to accept an additional argument for the patched target - e.g. mock_foo:

    @patch('MyClass.foo')
    def test_foo(self, mock_foo):
    
  3. You can then set the side effect on mock_foo:

    @patch('MyClass.foo')
    def test_foo(self, mock_foo):
        mock_foo.side_effect = self._side_effect_foo
    
  4. In addition, _side_effect_foo() should be made a proper instance method with self as the first argument:

    def _side_effect_foo(self, var1):
        if condition:
            return new_value
    
  5. Lastly, you should instantiate MyClass either inside the test method itself, or inside the setUp() method:

    def setUp(self):
        self.myClass = MyClass()
    
    @patch('MyClass.foo')
    def test_foo(self, mock_foo):
        mock_foo.side_effect = self._side_effect_foo
        self.myClass.bar()
    
2 of 2
0

An alternative to the accepted solution, more similar to the code in the question, is to use:

  1. @patch.object to patch an attribute of an object

  2. new=MagicMock(side_effect=...) to avoid passing the extra argument to the test function

Points 4. and 5. from Will Keeling's answer, about the side effect receiving self and instantiating MyClass in setUp, would still be important.

class TestClass(unittest.TestCase):
    def setUp(self):
        self.myClass = MyClass()

    @patch.object(MyClass, "foo", new=MagicMock(side_effect=_side_effect_foo))
    def test_foo(self):
        self.myClass.bar()


def _side_effect_foo(self, var1):
    if condition:
        return new_value
🌐
Python.org
discuss.python.org › ideas
Feat: unittest.Mock.side_effect fails on improper usage - Ideas - Discussions on Python.org
August 4, 2023 - What’s the problem this feature will solve? Mock.side_effect is tricky to use properly. Problem cases include: setting the value to an array of length less than two, in which case return_value is more readable and debuggable setting the value to an array of length n where the value doesn’t change.
🌐
GitHub
gist.github.com › kuntalchandra › f4c70e72740a18d2bb233b203f1c6399
Python: MagicMock, Patch and Side effect · GitHub
Python: MagicMock, Patch and Side effect · Raw · print_random.py · This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
🌐
Breadcrumbscollector
breadcrumbscollector.tech › how-to-mock-in-python-almost-definitive-guide
How to mock in Python? - (almost) definitive guide | breadcrumbs collector.tech
January 16, 2024 - If we combine this capability with classes defining __call__ method, we can mimic any behaviour we want with side_effect: from unittest.mock import Mock class ReturnValeusAllAround: def __init__(self, values): self._index = 0 self._values = values def __call__(self): return_value = self._values[self._index] self._index = (self._index + 1) % len(self._values) return return_value m = Mock(side_effect=ReturnValeusAllAround([1, 2, 3])) m() # 1 m() # 2 m() # 3 m() # 1 m() # 2 m() # ...
🌐
Thomas Stringer
trstringer.com › python-unit-test-mock-output
Change a Function's Output Based on Input Parameter Value in a Python Unit Test | Thomas Stringer
December 20, 2020 - Say, for example, we know (and want to validate) that an api_version with a value of "2020-01-01" passed to network_operation will result in an HTTPError. We want to make sure our function do_something is handling this correctly. Likewise, we want to test what do_something does with a “good” api_version. We can achieve this by levaraging the Mock.side_effect feature.