import time import unittest import concurrent.futures from test.support import threading_helper from unittest.mock import patch, ThreadingMock threading_helper.requires_working_threading(module=True) VERY_SHORT_TIMEOUT = 0.1 class Something: def method_1(self): pass # pragma: no cover def method_2(self): pass # pragma: no cover class TestThreadingMock(unittest.TestCase): def _call_after_delay(self, func, /, *args, **kwargs): time.sleep(kwargs.pop("delay")) func(*args, **kwargs) def setUp(self): self._executor = concurrent.futures.ThreadPoolExecutor(max_workers=5) def tearDown(self): self._executor.shutdown() def run_async(self, func, /, *args, delay=0, **kwargs): self._executor.submit( self._call_after_delay, func, *args, **kwargs, delay=delay ) def _make_mock(self, *args, **kwargs): return ThreadingMock(*args, **kwargs) def test_spec(self): waitable_mock = self._make_mock(spec=Something) with patch(f"{__name__}.Something", waitable_mock) as m: something = m() self.assertIsInstance(something.method_1, ThreadingMock) self.assertIsInstance(something.method_1().method_2(), ThreadingMock) with self.assertRaises(AttributeError): m.test def test_side_effect(self): waitable_mock = self._make_mock() with patch(f"{__name__}.Something", waitable_mock): something = Something() something.method_1.side_effect = [1] self.assertEqual(something.method_1(), 1) def test_instance_check(self): waitable_mock = self._make_mock() with patch(f"{__name__}.Something", waitable_mock): something = Something() self.assertIsInstance(something.method_1, ThreadingMock) self.assertIsInstance(something.method_1().method_2(), ThreadingMock) def test_dynamic_child_mocks_are_threading_mocks(self): waitable_mock = self._make_mock() self.assertIsInstance(waitable_mock.child, ThreadingMock) def test_dynamic_child_mocks_inherit_timeout(self): mock1 = self._make_mock() self.assertIs(mock1._mock_wait_timeout, None) mock2 = self._make_mock(timeout=2) self.assertEqual(mock2._mock_wait_timeout, 2) mock3 = self._make_mock(timeout=3) self.assertEqual(mock3._mock_wait_timeout, 3) self.assertIs(mock1.child._mock_wait_timeout, None) self.assertEqual(mock2.child._mock_wait_timeout, 2) self.assertEqual(mock3.child._mock_wait_timeout, 3) self.assertEqual(mock2.really().__mul__().complex._mock_wait_timeout, 2) def test_no_name_clash(self): waitable_mock = self._make_mock() waitable_mock._event = "myevent" waitable_mock.event = "myevent" waitable_mock.timeout = "mytimeout" waitable_mock("works") waitable_mock.wait_until_called() waitable_mock.wait_until_any_call_with("works") def test_patch(self): waitable_mock = self._make_mock(spec=Something) with patch(f"{__name__}.Something", waitable_mock): something = Something() something.method_1() something.method_1.wait_until_called() def test_wait_already_called_success(self): waitable_mock = self._make_mock(spec=Something) waitable_mock.method_1() waitable_mock.method_1.wait_until_called() waitable_mock.method_1.wait_until_any_call_with() waitable_mock.method_1.assert_called() def test_wait_until_called_success(self): waitable_mock = self._make_mock(spec=Something) self.run_async(waitable_mock.method_1, delay=VERY_SHORT_TIMEOUT) waitable_mock.method_1.wait_until_called() def test_wait_until_called_method_timeout(self): waitable_mock = self._make_mock(spec=Something) with self.assertRaises(AssertionError): waitable_mock.method_1.wait_until_called(timeout=VERY_SHORT_TIMEOUT) def test_wait_until_called_instance_timeout(self): waitable_mock = self._make_mock(spec=Something, timeout=VERY_SHORT_TIMEOUT) with self.assertRaises(AssertionError): waitable_mock.method_1.wait_until_called() def test_wait_until_called_global_timeout(self): with patch.object(ThreadingMock, "DEFAULT_TIMEOUT"): ThreadingMock.DEFAULT_TIMEOUT = VERY_SHORT_TIMEOUT waitable_mock = self._make_mock(spec=Something) with self.assertRaises(AssertionError): waitable_mock.method_1.wait_until_called() def test_wait_until_any_call_with_success(self): waitable_mock = self._make_mock() self.run_async(waitable_mock, delay=VERY_SHORT_TIMEOUT) waitable_mock.wait_until_any_call_with() def test_wait_until_any_call_with_instance_timeout(self): waitable_mock = self._make_mock(timeout=VERY_SHORT_TIMEOUT) with self.assertRaises(AssertionError): waitable_mock.wait_until_any_call_with() def test_wait_until_any_call_global_timeout(self): with patch.object(ThreadingMock, "DEFAULT_TIMEOUT"): ThreadingMock.DEFAULT_TIMEOUT = VERY_SHORT_TIMEOUT waitable_mock = self._make_mock() with self.assertRaises(AssertionError): waitable_mock.wait_until_any_call_with() def test_wait_until_any_call_positional(self): waitable_mock = self._make_mock(timeout=VERY_SHORT_TIMEOUT) waitable_mock.method_1(1, 2, 3) waitable_mock.method_1.wait_until_any_call_with(1, 2, 3) with self.assertRaises(AssertionError): waitable_mock.method_1.wait_until_any_call_with(2, 3, 1) with self.assertRaises(AssertionError): waitable_mock.method_1.wait_until_any_call_with() def test_wait_until_any_call_kw(self): waitable_mock = self._make_mock(timeout=VERY_SHORT_TIMEOUT) waitable_mock.method_1(a=1, b=2) waitable_mock.method_1.wait_until_any_call_with(a=1, b=2) with self.assertRaises(AssertionError): waitable_mock.method_1.wait_until_any_call_with(a=2, b=1) with self.assertRaises(AssertionError): waitable_mock.method_1.wait_until_any_call_with() def test_magic_methods_success(self): waitable_mock = self._make_mock() str(waitable_mock) waitable_mock.__str__.wait_until_called() waitable_mock.__str__.assert_called() def test_reset_mock_resets_wait(self): m = self._make_mock(timeout=VERY_SHORT_TIMEOUT) with self.assertRaises(AssertionError): m.wait_until_called() with self.assertRaises(AssertionError): m.wait_until_any_call_with() m() m.wait_until_called() m.wait_until_any_call_with() m.assert_called_once() m.reset_mock() with self.assertRaises(AssertionError): m.wait_until_called() with self.assertRaises(AssertionError): m.wait_until_any_call_with() m() m.wait_until_called() m.wait_until_any_call_with() m.assert_called_once() if __name__ == "__main__": unittest.main()