Angenommen, es gibt zwei Pakete in einem Projekt: some_package
und another_package
.Pytest Monkeypatch funktioniert nicht bei importierter Funktion
# some_package/foo.py:
def bar():
print('hello')
# another_package/function.py
from some_package.foo import bar
def call_bar():
# ... code ...
bar()
# ... code ...
Ich möchte another_package.function.call_bar
testen some_package.foo.bar
spöttisch, weil sie auf das Netzwerk hat I/O ich vermeiden wollen. Hier
ist ein 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
Zu meiner Überraschung gibt sie hello
statt mock
. Ich habe versucht, diese Sache zu debuggen, die ipdb Haltepunkt im Test setzt. Wenn ich manuell some_package.foo.bar
nach Breakpoint importieren und rufen bar()
ich patched
.
Bei meinem realen Projekt ist die Situation noch interessanter. Wenn ich Pytest im Projektstamm aufrufen, wird meine Funktion nicht gepatcht, aber wenn ich tests/test_bar.py
als Argument festlege - funktioniert es.
Soweit ich verstehe, hat es etwas mit der from some_package.foo import bar
Aussage zu tun. Wenn es ausgeführt wird, bevor Monkeypatching stattfindet, schlägt das Patchen fehl. Bei dem verdichteten Testaufbau aus dem obigen Beispiel funktioniert das Patching jedoch nicht in beiden Fällen.
Und warum funktioniert es in IPDB REPL nach dem Treffen eines Haltepunkts?
Dies ist einer der schlimmsten Fehler mit Pytest - aber danke für die Erklärung. –
Wenn Sie "use module.bar" sagen, können Sie ein Codebeispiel angeben? Ich habe 'monkeypatch.setattr (Modul, 'bar', mock_obj)' und ein paar andere Beschwörungen ohne Erfolg versucht. – skolsuper
Vielen Dank für Ihre Antwort. Gibt es einen Trick, um sicher zu sein, dass jeder Import ein verspottetes Objekt verwendet? Denn jetzt ist es gefährlich, wenn ich zum Beispiel versuche, Objekt – Stavinsky