Luego de de una extensa compilación de información dimos con la respuesta esta inconveniente que suelen tener muchos de nuestros usuarios. Te dejamos la respuesta y esperamos servirte de mucha ayuda.
Solución:
Necesita parchear la función datetime.now. En el siguiente ejemplo, estoy creando un accesorio que puedo reutilizar más tarde en otras pruebas:
import datetime
import pytest
FAKE_TIME = datetime.datetime(2020, 12, 25, 17, 5, 55)
@pytest.fixture
def patch_datetime_now(monkeypatch):
class mydatetime:
@classmethod
def now(cls):
return FAKE_TIME
monkeypatch.setattr(datetime, 'datetime', mydatetime)
def test_patch_datetime(patch_datetime_now):
assert datetime.datetime.now() == FAKE_TIME
Hay freezegun
módulo:
from datetime import datetime
from freezegun import freeze_time # $ pip install freezegun
@freeze_time("Jan 14th, 2012")
def test_nice_datetime():
assert datetime.now() == datetime(2012, 1, 14)
freeze_time()
también podría usarse como administrador de contexto. El módulo admite la especificación del desplazamiento UTC de la zona horaria local.
Este es el accesorio que uso para anular ahora () pero manteniendo el resto de la fecha y hora funcionando (RE: pregunta de satoru).
No se ha probado de forma exhaustiva, pero soluciona problemas en los que la fecha y hora se utiliza en otros contextos. Para mí, esto era importante para mantener el ORM de Django funcionando con estos valores de fecha y hora (específicamente isinstance(Freeze.now(), datetime.datetime) == True
).
@pytest.fixture
def freeze(monkeypatch):
""" Now() manager patches datetime return a fixed, settable, value
(freezes time)
"""
import datetime
original = datetime.datetime
class FreezeMeta(type):
def __instancecheck__(self, instance):
if type(instance) == original or type(instance) == Freeze:
return True
class Freeze(datetime.datetime):
__metaclass__ = FreezeMeta
@classmethod
def freeze(cls, val):
cls.frozen = val
@classmethod
def now(cls):
return cls.frozen
@classmethod
def delta(cls, timedelta=None, **kwargs):
""" Moves time fwd/bwd by the delta"""
from datetime import timedelta as td
if not timedelta:
timedelta = td(**kwargs)
cls.frozen += timedelta
monkeypatch.setattr(datetime, 'datetime', Freeze)
Freeze.freeze(original.now())
return Freeze
Quizás fuera de tema, pero podría ser útil para otras personas que lleguen a esta pregunta. Este dispositivo permite “congelar” el tiempo y luego moverlo hacia adelante y hacia atrás a voluntad dentro de sus pruebas:
def test_timesensitive(freeze):
freeze.freeze(2015, 1, 1)
foo.prepare() # Uses datetime.now() to prepare its state
freeze.delta(days=2)
# Does something that takes in consideration that 2 days have passed
# i.e. datetime.now() returns a date 2 days in the future
foo.do_something()
assert foo.result == expected_result_after_2_days
Si te ha resultado de provecho este post, sería de mucha ayuda si lo compartieras con más seniors y nos ayudes a dar difusión a este contenido.