Saltar al contenido

¿Cómo parchear el datetime.datetime.now de python con py.test?

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.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *