How to handle the callback with MagicMock

41 Views Asked by At
import unittest
from mock import Mock, MagicMock
import time

wait = False

def pushback_callback(self, res):
  print("Received callback")
  wait = True
  
def pushback_fcn(callback):
  print("pushback_fcn")
  
def execute():
  pushback_fcn(pushback_callback)
  while wait == False:
      time.sleep(5)
      
  print("done")
            
#********* Test code ************#
pushback_fcn = MagicMock()
execute()

As test code never call the callback, wait value is False always hence the test code wait forever. Is there any way we can get the function pointer form MagicMock?

1

There are 1 best solutions below

0
Martin Schaer On

I created a similar code to test mocking a function that receives a callback. Install and run pytest to test it out.

The way the callback is mocked is by using @patch and side_effect (documentation about how patch and side_effect work)

The script includes 2 tests, one without the mock and one with it (changing the value sent through the callback from done to mocked).

from unittest.mock import patch
import threading
import time

event = threading.Event()
result = "pending"


def on_finished(msg):
    global result
    result = msg


def async_fn(callback):
    time.sleep(1)
    event.set()
    callback("done")


def execute():
    async_fn(on_finished)
    event.wait()
    print(f"done with result: {result}")

# ============================================================
# Tests


def test_without_mock():
    execute()
    assert result == "done"


@patch("test_mock_fn_with_callback.async_fn")
def test_with_mock(async_fn):
    async_fn.side_effect = lambda callback: callback("mocked")
    execute()
    assert result == "mocked"