Is it possible to mock.patch
a function that will be run in a subprocess, which is created using the multiprocessing
module with the start method
set to spawn
?
If there is no solution to patching a child process which is not forked
, what would be the right solution to bypass this problem?
It's important to say that switching to use fork is not a solution to my problem.
As of python3.8-macOS, the default behavior for the multiprocessing start method is spawn
.
From the multiprocessing
documentation:
Changed in version 3.8: On macOS, the spawn start method is now the default. The fork start method should be considered unsafe as it can lead to crashes of the subprocess. See bpo-33725.
.
Example code (Run on macos with python >= 3.8):
import multiprocessing
import unittest
from unittest import mock
def baz(i):
print(i)
def bar(i): # Middle function to avoid a pickeling problem with mocks
baz(i)
def foo():
with multiprocessing.Pool(2) as pool:
pool.map(bar, [i for i in range(10)])
class TestClass(unittest.TestCase):
@mock.patch(f'{__name__}.baz', return_value=None)
def test_case(self, mock):
# multiprocessing.set_start_method('fork', force=True)
foo()
The baz
function is not patched in the spawned processes (and hence, it prints) as can be seen in the following output.
Changing the default start method (commented in code) solves the problem
Output:
============================================================================== test session starts ===============================================================================
platform darwin -- Python 3.8.0, pytest-5.4.3, py-1.8.2, pluggy-0.13.1
rootdir: /Users/alonmenczer/dev/path_test/proj
collected 1 item
mp_spawn.py 0
1
4
5
6
7
8
9
2
3
.
=============================================================================== 1 passed in 0.27s ================================================================================