Sie versuchen, zu verspotten datetime.Datum.heute(), aber funktioniert nicht
Kann mir jemand sagen warum das nicht funktioniert?
>>> import mock
>>> @mock.patch('datetime.date.today')
... def today(cls):
... return date(2010, 1, 1)
...
>>> from datetime import date
>>> date.today()
datetime.date(2010, 12, 19)
Vielleicht könnte jemand empfehlen, einen besseren Weg?
- Docs der
mock
Bibliothek: voidspace.org.uk/python/mock/Beispiele.html#partial-mocking - freezegun
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gibt es ein paar Probleme.
Zunächst, die Art und Weise, die Sie verwenden
mock.patch
ist nicht ganz richtig. Wenn verwendet, als Dekorateur, ersetzt es die Funktion/Klasse (in diesem Falldatetime.date.today
) mit einemMock
Objekt nur innerhalb der eingerichteten Funktion. So, nur innerhalb Ihrertoday()
wirddatetime.date.today
eine andere Funktion, die scheint nicht zu sein, was Sie wollen.Was Sie wirklich wollen, scheint zu sein, eher wie dieser:
Leider funktioniert es nicht:
Dies schlägt fehl, da Python built-in-Typen sind unveränderlich, siehe diese Antwort für mehr details.
In diesem Fall würde ich eine Unterklasse datetime.date mich und erstellen Sie die Funktion right:
Ist und du jetzt tun könnte:
datetime
Instanz zu es ursprüngliche Wert? mitdeepcoppy
?patch('mymodule.datetime', Mock(today=lambda: date(2017, 11, 29)))
@patch('module_you_want_to_test.date', Mock( today=Mock(return_value=datetime.date(2017, 11, 29))))
.@mock.patch('datetime.date', NewDate)
stattdatetime.date = NewDate
Andere Möglichkeit ist die Verwendung
https://github.com/spulec/freezegun/
Installieren:
Und Verwendung:
Es betrifft auch die anderen datetime-Aufrufe in Methoden-Aufrufe aus anderen Modulen:
other_module.py:
main.py:
Und schließlich:
Für was es Wert ist, die Mock-docs reden datetime.Datum.heute speziell, und es ist möglich dies zu tun, ohne zu müssen, erstellen Sie eine dummy-Klasse:
https://docs.python.org/3/library/unittest.mock-examples.html#partial-mocking
from datetime import date
dann ist es der name des Moduls, wo derfrom datetime import date
und der Aufrufdate.today()
erscheint@patch('mymodule.date', autospec=True)
Auch ich glaube nicht, dass die Nebenwirkung lambda ist in diesem Fall verpflichtetIch denke, ich kam ein wenig zu spät dafür, aber ich denke, das Hauptproblem hier ist, dass Sie das patchen datetime.Datum.heute direkt und, laut der Dokumentation, das ist falsch.
Sollten Sie den patch Referenz importiert in der Datei, wo die Funktion getestet ist, zum Beispiel.
Lassen Sie uns sagen, Sie haben eine functions.py Datei, in dem Sie die folgenden:
dann in Ihrer Prüfung sollten Sie so etwas haben
Hoffe, das hilft ein wenig.
NameError: name 'datetime' is not defined
). Wo kommt diedatetime.strptime
Referenz inMock(return_value=...)
kommen aus, wenn Sie nicht importierendatetime
im test-Datei? UPDATE: Es ist OK, ich ging einfach weiter und importiert diedatetime
Modul in der test-Datei. Ich dachte, der trick war, einige, wie die, dass Sie versteckt sind diedatetime
Verweis aus der test-Datei.import datetime
oderfrom datetime import strptime
? wenn Sie Taten, waren die ersten, die Sie haben würden, zu verspottendatetime
und tunmocked_datetime.strptime.return_value = whatever
, ist die spätere, Sie müssten direkt mock der strptime-Referenz in der Datei, wo die erprobte Methode lebt.Mock(return_value=datetime...)
Arbeit.Hinzufügen Daniel G ' s Lösung:
Dieser erstellt eine Klasse, die, wenn instanziiert, wird wieder eine normale datetime.date-Objekt, aber die ist auch die können geändert werden.
date
/datetime
selbst, es verwendet die Global verfügbare variable, so sollte es kein problem sein: dpaste.com/790310Sie können verwenden Sie die folgende Vorgehensweise, basierend auf Daniel G Lösung. Dieser hat den Vorteil, nicht zu brechen Typprüfung mit
isinstance(d, datetime.date)
.Grundsätzlich ersetzen wir C-basierten
datetime.date
Klasse mit eigenen python-Unterklasse, produziert originaldatetime.date
Instanzen und reagiert aufisinstance()
Abfragen genau wie nativedatetime.date
.Verwenden Sie es als Kontext-manager in Ihren tests:
Ähnlicher Ansatz kann verwendet werden, um mock
datetime.datetime.now()
Funktion.__instancecheck__
Methode.Stand ich vor der gleichen situation vor ein paar Tagen, und meine Lösung war es, eine Funktion definieren, die in das Modul zu testen und nur spotten, dass:
Heute fand ich heraus, über FreezeGun, und es scheint, dass es für diesen Fall wunderschön
Ist der einfachste Weg für mich ist, dies zu tun:
ACHTUNG für diese Lösung: alle Funktionen von
datetime module
von dertarget_module
aufhören zu arbeiten.datetime_mock.now = Mock(return_value=datetime(1999, 1, 1)
könnten sogar verkürzt werden, umdatetime_mock.now.return_value = datetime(1999, 1, 1)
. Statt zu starten den patch mitstart()
, sollten Sie diewith patch(...):
Kontext-manager, um sicherzustellen, dassdatetime
verhält regelmäßige (unmocked) wieder, wenn Ihr test beendet.datetime.datetime.now()
unmocked ^^?datetime module
von dertarget_module
aufhören zu arbeiten.with patch(...):
Kontext-managerAllgemein gesprochen, würden Sie haben
datetime
oder vielleichtdatetime.date
importiert ein Modul irgendwo. Ein effektiver Weg, verspotten die Methode wäre, um den patch auf das Modul, das Sie es importieren. Beispiel:ein.py
Dann für Ihren test, das mock-Objekt selbst übergeben werden würde, als argument für die test-Methode. Sie würde die mock-mit dem Ergebnis Wert, den Sie wollen, und dann rufen Sie Ihre Methode im test. Dann würden Sie behaupten, dass Ihre Methode haben, was Sie wollen.
Ein Wort der Warnung. Es ist sicherlich möglich, über Bord zu gehen mit Spott. Wenn Sie das tun, Sie macht Ihre tests länger, schwerer zu verstehen und unmöglich zu pflegen. Bevor Sie verspotten ein Verfahren so einfach wie
datetime.date.today
, Fragen Sie sich, ob Sie wirklich müssen zu verspotten es. Wenn Ihr test ist kurz und auf den Punkt und funktioniert gut, ohne Spott die Funktion, Sie kann nur sein, den Blick auf ein internes detail von dem code, den Sie testen gerade, eher als ein Objekt, das Sie brauchen, zu verspotten.Mehrere Lösungen diskutiert werden,http://blog.xelnor.net/python-mocking-datetime/. Zusammenfassend:
Mock-Objekt - Einfach und effizient, sondern bricht isinstance() überprüft:
Mock-Klasse
Verwendung als:
Vielleicht könnten Sie Ihre eigene "heute ()" - Methode, dass Sie den patch wo Sie benötigt wird. Beispiel mit Spott utcnow() kann hier gefunden werden: https://bitbucket.org/k_bx/blog/src/tip/source/en_posts/2012-07-13-double-call-hack.rst?at=default
Ich umgesetzt @user3016183-Methode mit einer benutzerdefinierten decorator:
Ich dachte das könnte jemand helfen, eines Tages...
Ist es möglich, zu verspotten Funktionen von
datetime
Modul ohne Zugabeside_effects
Hier ist ein weiterer Weg, zu verspotten
datetime.date.today()
mit einem zusätzlichen bonus, dass der rest derdatetime
Funktionen weiter zu arbeiten, als die mock-Objekt konfiguriert ist, um wickeln Sie die originaldatetime
Modul:Hinweis: die
wraps=datetime
argumentmock.patch()
– wenn diefoo_module
verwendet anderedatetime
Funktionen nebendate.today()
Sie werden an den original-verpacktdatetime
Modul.Für diejenigen von Euch pytest mit mocker hier ist, wie ich verspottet
datetime.datetime.now()
die sehr ähnlich zu der ursprünglichen Frage.Im wesentlichen die mock gesetzt werden muss, um die Rückkehr des angegebenen Datums. Sie sind nicht in der Lage, um den patch über datetime-Objekt direkt.