Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
333 views
in Technique[技术] by (71.8m points)

python - Pytest monkeypatch isn't working on imported function

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?

question from:https://stackoverflow.com/questions/31306080/pytest-monkeypatch-isnt-working-on-imported-function

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...