◐ Shell
clean mode source ↗

[WIP] bpo-17013: Implement WaitableMock to create Mock objects that can wait until called by tirkarthi · Pull Request #12818 · python/cpython

Another problem is that inside wait_until_called_with I create event objects and calling self._event_class and so on seems to record the calls to the Mock object too. But this is not a problem with wait_until_called where not such attribute access is done. I guess there is some flaw in my approach of attribute access with self leading to this.

import threading
import time
from unittest.mock import WaitableMock, patch, call

def call_after_sometime(func, *args, delay=1):
    time.sleep(delay)
    func(*args)

def foo(*args):
    pass

def bar(*args):
    pass

with patch('__main__.foo', WaitableMock(event_class=threading.Event)):
    with patch('__main__.bar', WaitableMock(event_class=threading.Event)):
        threading.Thread(target=call_after_sometime, args=(foo, 1), kwargs={'delay': 1}).start()
        threading.Thread(target=call_after_sometime, args=(bar, 2), kwargs={'delay': 1}).start()
        print("bar called with 1 ", bar.wait_until_called_with(2, timeout=2))
        print(bar.mock_calls)
        bar.assert_called_once_with(2)
        print("foo called with 1 ", foo.wait_until_called_with(timeout=2))
        print(foo.mock_calls)
bar called with 1  <WaitableMock name='mock._event_class().is_set()' id='4461405584'>
[call.expected_calls.__contains__((2,)),
 call._event_class(),
 call._event_class().is_set(),
 call._event_class().is_set().__bool__(),
 call._event_class().is_set().__str__()]
Traceback (most recent call last):
  File "../backups/bpo17013_mock_1.py", line 25, in <module>
    bar.assert_called_once_with(2)
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/unittest/mock.py", line 852, in assert_called_once_with
    raise AssertionError(msg)
AssertionError: Expected 'mock' to be called once. Called 0 times.
Calls: [call.expected_calls.__contains__((2,)),
 call._event_class(),
 call._event_class().is_set(),
 call._event_class().is_set().__bool__(),
 call._event_class().is_set().__str__()].

For foo it would work fine :

foo called with 1  True
[call(1)]

calls to foo return true and correct call objects. Meanwhile calls to bar with wait_until_called_with cause irrelevant calls to be recorded. Is there something I am missing or some setup in configuring the mock that I have missed?

I think there is a flaw that I have added time.sleep in my examples and calls are made misleading me and perhaps the mock object never waits for wait_until_called_with calls and the assertion error is telling me the same? If I add sleep it works fine.