Pytest monkeypatch isn't working on imported function

Solution 1:

While Ronny's answer works it forces you to change application code. In general you should not do this for the sake of testing.

Instead you can explicitly patch the object in the second package. This is mentioned in the docs for the unittest module.

monkeypatch.setattr('another_package.bar', lambda: print('patched'))

Solution 2:

As Alex said, you shouldn't rewrite your code for your tests. The gotcha I ran into is which path to patch.

Given the code:

app/handlers/tasks.py

from auth.service import check_user

def handle_tasks_create(request):
  check_user(request.get('user_id'))
  create_task(request.body)
  return {'status': 'success'}

Your first instinct to monkeypatch check_user, like this:

monkeypatch.setattr('auth.service.check_user', lambda x: return None)

But what you want to do is patch the instance in tasks.py. Likely this is what you want:

monkeypatch.setattr('app.handlers.tasks.check_user', lambda x: return None)

While the answers given are already good, I hope this brings more complete context.

Solution 3:

Named importation creates a new name for the object. If you then replace the old name for the object the new name is unaffected.

Import the module and use module.bar instead. That will always use the current object.


EDIT:

import module 

def func_under_test():
  module.foo()

def test_func():
   monkeypatch.setattr(...)
   func_under_test

Solution 4:

correct answer to OP's question:

monkeypatch.setattr('another_package.function.bar', lambda: print('patched'))