1

An instance of class A starts a sub-process that calls a method of an instance of class B. It works as expected in real-life, but unit tests fail because the mock object replacing the object of class B does not report being called.

Minimal code:

from multiprocessing import Process

class Main:
    def __init__(self, mock):
        self._mock = mock
        process = Process(target=self.task)
        process.start()
        process.join()

    def task(self):
        self._mock.method()

Tests:

from unittest.mock import Mock
from MinimalCode import Main

mock = Mock(unsafe=True)
def test_process():
    main = Main(mock)
    mock.method.assert_called()

Pytest result:

_____________________________________________________________ ERROR collecting test_Process.py ______________________________________________________________
test_Process.py:9: in <module>
    test_process()
test_Process.py:7: in test_process
    mock.method.assert_called()
/usr/lib/python3.11/unittest/mock.py:902: in assert_called
    raise AssertionError(msg)
E   AssertionError: Expected 'method' to have been called.

How should I write tests for mocks called in subprocesses ?

2
  • 2
    Mostly, you don't – since it's a separate process, it has a separate Python interpreter, and things like mocks in the parent process have no effect on it. If you're just trying to make a function call, can you directly call it, without involving multiprocessing or subprocess? Can you make the concurrency layer pluggable so that you can use a direct function call in tests? Commented Dec 14 at 21:15
  • 2
    This question is similar to: How to use mock in function run in multiprocessing.Pool. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Dec 15 at 0:57

1 Answer 1

0

As noted in comments the design you have simply won't work nicely, if at all with multiprocessing because you have a new interpreter, so the mock instances from the host process won't affect them!

Instead, consider

  • using a Thread instead of a Process, especially considering if you can mock or monkeypatch it - this will share the host namespace and can be mocked.. this is likely the least code change, but if you're using a new process to avoid changes to the host namespaces, you're stuck unless you jump through more hoops to stub them out
  • call the inner logic directly instead - practically, you have an integration test, not a unit test as-designed, can you test the functionality closer to exact code site?
  • change the output of the subprocess when under test, ie. forcing the return of some flag for success or failure
Sign up to request clarification or add additional context in comments.

3 Comments

I'm using a Process to bypass the GIL restrictions on Threads. How can I return a signal from the subprocess ?
hmm.. how are you sending back information now? and are you doing perf in your unittest? just a humble print() is often enough with docs.python.org/3/library/… unless you mean literally the signal subsystem
I'm not sending anything back now (not needed outside of testing).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.