Pytest monkeypatch isn't working on imported function

pytest monkeypatch vs mock
pytest monkeypatch example
pytest monkeypatch import
pytest patch
pytest mocker
pytest monkeypatch not working
nameerror: name 'monkeypatch' is not defined
pytest monkeypatch environment variables

Suppose there are two packages in a project: some_package and another_package.

# some_package/foo.py:
def bar():
    print('hello')
# another_package/function.py
from some_package.foo import bar

def call_bar():
    # ... code ...
    bar()
    # ... code ...

I want to test another_package.function.call_bar mocking out some_package.foo.bar because it has some network I/O I want to avoid.

Here is a test:

# tests/test_bar.py
from another_package.function import call_bar

def test_bar(monkeypatch):
    monkeypatch.setattr('some_package.foo.bar', lambda: print('patched'))
    call_bar()
    assert True

To my surprise it outputs hello instead of patched. I tried to debug this thing, putting an IPDB breakpoint in the test. When I manually import some_package.foo.bar after the breakpoint and call bar() I get patched.

On my real project the situation is even more interesting. If I invoke pytest in the project root my function isn't patched, but when I specify tests/test_bar.py as an argument - it works.

As far as I understand it has something to do with the from some_package.foo import bar statement. If it's being executed before monkeypatching is happening then patching fails. But on the condensed test setup from the example above patching does not work in both cases.

And why does it work in IPDB REPL after hitting a breakpoint?

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

Pytest monkeypatch isn't working on imported function, The monkeypatch fixture helps you to safely set/delete an attribute, dictionary Be advised that it is not recommended to patch builtin functions such as open� Use monkeypatch.setitem() to patch the dictionary for the test. monkeypatch.delitem() can be used to remove items. 3. Modifying environment variables for a test e.g. to test program behavior if an environment variable is missing, or to set multiple values to a known variable. monkeypatch.setenv() and monkeypatch.delenv() can be used for these

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'))

Monkeypatching with pytest – Patrick's Software Blog, 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� Pytest monkeypatch isn't working on imported function. Ask Question Asked 4 years, 9 months ago. Active 5 months ago. Viewed 8k times 29. 13. Suppose there

correct answer to OP's question:

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

Mocking, Monkey Patching, and Faking Functionality — Python 401 , to use the monkeypatch fixture in pytest, so I wanted to write a blog post This test function utilizes the 'monkeypatch' fixture that is part of� @contextmanager def context (self)-> Generator ["MonkeyPatch", None, None]: """ Context manager that returns a new :class:`MonkeyPatch` object which undoes any patching done inside the ``with`` block upon exit:.. code-block:: python import functools def test_partial(monkeypatch): with monkeypatch.context() as m: m.setattr(functools, "partial", 3) Useful in situations where it is desired to

monkeypatch doesn't patch a module if it has already been imported , monkeypatch is a part of the pytest-mock library that allows you to intercept what In our test file, we can “monkey patch” the call to GitHub's API. we can do this� monkeypatch is a part of the pytest-mock library that allows you to intercept what a function would normally do, substituting its full execution with a return value of your own specification. Note that monkey patching a function call does not count as actually testing that function call!

Mocks and Monkeypatching in Python, That's a common gotcha with mocking in Python, and is not particular to monkeypatch but affects also other mocking modules including� from handlers.UserDetails import user_login_required @pytest.mark.parametrize('params', get_params, ids=get_ids) def test_post(self, params, monkeypatch): monkeypatch.setattr(user_login_required, mock_user_login_required_func) The problem with this is that monkeypatch does not allow me to put a single function in as the target.

Pytest monkeypatch : Python, This tutorial will help you understand why mocking is important, and show you how to mock in Python with Mock and Pytest monkeypatch. pytest provides a monkeypatch fixture to replace values and behaviors, If you built your test suite from scratch in pytest, then this isn’t very likely.

Comments
  • This is among the worst gotchas with pytest — but thanks for explaining it.
  • When you say "use module.bar", can you provide a code example? I have tried monkeypatch.setattr(module, 'bar', mock_obj) and a few other incantations without success.
  • Thank you for your answer. Is there something trick to be sure that any import will use mocked object. Because for now it is dangerous if, for example I'm trying to mock orm object
  • this is a property of the python language and there is no trick
  • This is clearly the cleaner way of monkeypatching an import.
  • The link is to the wrong docs as far as I can tell. It should be to the pytest monkeypatch docs.
  • @LondonRob the unit-test docs have an explanation for why patching is a good idea