Patching a method from other file is not working

Question:

I have a method say _select_warehouse_for_order in api/controllers/orders.py file. The method is not part of any class.

Now, I have a new file say api/controllers/dispatchers.py where i need to know which warehouse was selected. I am calling _select_warehouse_for_order from this file to get this information.

Now, in my test cases, I am patching _select_warehouse_for_order like this

from unittest.mock import patch, call

def test_delivery_assignment(self, app_context):
    with patch('api.controllers.orders._select_warehouse_for_order') as mock_selected_wh:
        mock_selected_wh.return_value = {}
        app_context.client.set_url_prefix('/v2')
        response = app_context.client.get('/delivery/dispatch')
        assert response.status_code == 200

The problem that i am facing is that my patch is not returning empty dictionary. when i started debugging, i noticed that its executed the actual code in _select_warehouse_for_order. Am i missing something here?

Update:
Here is the code in dispatchers.py

from api.controllers.orders import _select_warehouse_for_order

@bp.route("/dispatch")
@login_required
def dispatch():
  warehouses = _select_warehouse_for_order(request=request)
    if len(warehouses) == 0:
        logger.info("No warehouse selected")
        return

    logger.info("Selected warehouse: %s", warehouses[0].name)
    # return response
Asked By: Em Ae

||

Answers:

You must patch where the method is used, not where it is declared. In your case, you are patching 'api.controllers.orders._select_warehouse_for_order' which is where the method is declared. Instead, patch 'dispatchers._select_warehouse_for_order' (possibly prefixed with whatever package contains dispatchers).

The reason for this is because when you do

from api.controllers.orders import _select_warehouse_for_order

you declare a name _select_warehouse_for_order in dispatchers.py that refers to the function which is declared in api/controllers/orders.py. Essentially you have created a second reference to the function. Now when you call

  warehouses = _select_warehouse_for_order(request=request)

you are using the reference in dispatchers.py, not the one in api/controllers/orders.py. So in order to replace this function with a patch, you have to use dispatchers._select_warehouse_for_order.

Notice how import is different in python than in Java because we create a new name and assign it to an existing function or class. On the other hand, Java imports tell the compiler where to look for a class when it is mentioned in the code.

Answered By: Code-Apprentice