¿Alguien puede decirme por qué esto no funciona?
>>> 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)
Tal vez alguien podría sugerir una mejor manera?

mockbiblioteca: voidspace.org.uk/python/mock/examples.html#partial-mockingRespuestas:
Hay algunos problemas
En primer lugar, la forma en que está utilizando
mock.patchno es del todo correcta. Cuando se usa como decorador, reemplaza la función / clase dada (en este casodatetime.date.today) con unMockobjeto solo dentro de la función decorada . Entonces, solo dentro de ustedtoday()habrádatetime.date.todayuna función diferente, que no parece ser lo que desea.Lo que realmente quieres parece ser más así:
Desafortunadamente, esto no funcionará:
Esto falla porque los tipos integrados de Python son inmutables; consulte esta respuesta para obtener más detalles.
En este caso, subclase datetime.date yo mismo y cree la función correcta:
Y ahora puedes hacer:
fuente
datetimeinstancia a su valor original? condeepcoppy?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)))).Otra opción es usar https://github.com/spulec/freezegun/
Instalarlo:
Y úsalo:
También afecta a otras llamadas de fecha y hora en llamadas a métodos de otros módulos:
other_module.py:
main.py:
Y finalmente:
fuente
Por lo que vale, los documentos simulados hablan específicamente de datetime.date.today, y es posible hacer esto sin tener que crear una clase ficticia:
https://docs.python.org/3/library/unittest.mock-examples.html#partial-mocking
fuente
from datetime import dateentonces es el nombre del módulo donde aparecefrom datetime import datey la llamada adate.today()Supongo que llegué un poco tarde para esto, pero creo que el problema principal aquí es que estás parcheando datetime.date.today directamente y, según la documentación, esto está mal.
Debe parchear la referencia importada en el archivo donde se encuentra la función probada, por ejemplo.
Supongamos que tiene un archivo functions.py donde tiene lo siguiente:
entonces, en tu prueba, deberías tener algo como esto
Espero que esto ayude un poco.
fuente
NameError: name 'datetime' is not defined). ¿De dónde viene ladatetime.strptimereferenciaMock(return_value=...)si no está importandodatetimeen su archivo de prueba? ACTUALIZACIÓN: Está bien, simplemente seguí adelante e importé eldatetimemódulo en el archivo de prueba. Pensé que el truco era cómo ocultas ladatetimereferencia del archivo de prueba.import datetimeofrom datetime import strptime? si estuviera haciendo el primero, tendría que burlarsedatetimey hacermocked_datetime.strptime.return_value = whatever, es el último, tendría que burlarse directamente de la referencia de strptime en el archivo donde vive el método probado.Mock(return_value=datetime...)funcione.Para agregar a la solución de Daniel G :
Esto crea una clase que, cuando se instancia, devolverá un objeto datetime.date normal, pero que también se puede cambiar.
fuente
date/datetimeutiliza, utiliza la variable disponible globalmente, por lo que no debería haber ningún problema: dpaste.com/790310Me enfrenté a la misma situación hace un par de días, y mi solución fue definir una función en el módulo para probar y simplemente burlarme de eso:
Hoy me enteré de FreezeGun , y parece cubrir este caso maravillosamente
fuente
La forma más fácil para mí es hacer esto:
PRECAUCIÓN para esta solución: toda la funcionalidad
datetime modulede latarget_moduledejará de funcionar.fuente
datetime_mock.now = Mock(return_value=datetime(1999, 1, 1)incluso podría acortarsedatetime_mock.now.return_value = datetime(1999, 1, 1). En lugar de comenzar el parche constart(), considere usar elwith patch(...):administrador de contexto para asegurarse de que sedatetimecomporta regularmente (sin desbloquear) nuevamente cuando finaliza la prueba.datetime.datetime.now()desbloquear ^^?datetime moduledesde eltarget_moduledejarán de funcionar.Puede usar el siguiente enfoque, basado en la solución Daniel G. Este tiene la ventaja de no romper la verificación de tipos con
isinstance(d, datetime.date).Básicamente, reemplazamos la
datetime.dateclase basada en C con nuestra propia subclase de Python, que producedatetime.dateinstancias originales y responde a lasisinstance()consultas exactamente como nativasdatetime.date.Úselo como administrador de contexto en sus pruebas:
Se puede utilizar un enfoque similar para burlarse de la
datetime.datetime.now()función.fuente
__instancecheck__método.En términos generales, tendrías
datetimeo quizásdatetime.dateimportado importado a un módulo en alguna parte. Una forma más efectiva de burlarse del método sería parchearlo en el módulo que lo está importando. Ejemplo:a.py
Luego, para su prueba, el objeto simulado se pasaría como un argumento al método de prueba. Debería configurar el simulacro con el valor de resultado que desea y luego llamar a su método bajo prueba. Luego afirmarías que tu método hizo lo que quieres.
Una palabra de advertencia. Es ciertamente posible ir por la borda con burla. Cuando lo hace, hace que sus pruebas sean más largas, más difíciles de entender e imposibles de mantener. Antes de burlarse de un método tan simple como
datetime.date.today, pregúntese si realmente necesita burlarse de él. Si su prueba es corta y va al grano y funciona bien sin burlarse de la función, es posible que solo esté mirando un detalle interno del código que está probando en lugar de un objeto que necesita burlarse.fuente
Aquí hay otra forma de simular
datetime.date.today()con una ventaja adicional de que el resto dedatetimefunciones continúan funcionando, ya que el objeto simulado está configurado para envolver eldatetimemódulo original :Tenga en cuenta el
wraps=datetimeargumento demock.patch(): cuandofoo_moduleutiliza otrasdatetimefunciones además dedate.today()que se enviarán aldatetimemódulo original envuelto .fuente
Se discuten varias soluciones en http://blog.xelnor.net/python-mocking-datetime/ . En resumen:
Objeto simulado: simple y eficiente, pero rompe las comprobaciones isinstance ():
Clase simulada
Usar como:
fuente
Tal vez podría usar su propio método "today ()" que parcheará cuando sea necesario. Puede encontrar un ejemplo con burlarse de utcnow () aquí: https://bitbucket.org/k_bx/blog/src/tip/source/en_posts/2012-07-13-double-call-hack.rst?at=default
fuente
Implementé el método @ user3016183 usando un decorador personalizado:
Pensé que eso podría ayudar a alguien algún día ...
fuente
Es posible simular funciones del
datetimemódulo sin agregarside_effectsfuente
Para aquellos de ustedes que usan pytest con burlador, aquí es cómo me burlé,
datetime.datetime.now()que es muy similar a la pregunta original.Esencialmente, el simulacro debe configurarse para devolver la fecha especificada. No puede parchear sobre el objeto de datetime directamente.
fuente
Hice este trabajo mediante la importación
datetimecomorealdatetimey la sustitución de los métodos que se necesitan en la maqueta con los métodos reales:fuente
Puedes burlarte de
datetimeesto:En el modulo
sources.py:En su
tests.py:fuente
sourcesen tu decorador de parches?CPython realmente implementa el módulo datetime utilizando tanto Python Lib / datetime.py puro como Módulos optimizados en C / _datetimemodule.c . La versión optimizada en C no se puede parchear, pero la versión pura de Python sí.
En la parte inferior de la implementación de Python puro en Lib / datetime.py se encuentra este código:
Este código importa todas las definiciones optimizadas en C y reemplaza efectivamente todas las definiciones de Python puro. Podemos obligar a CPython a usar la implementación de Python puro del módulo datetime haciendo lo siguiente:
Al configurar
sys.modules["_datetime"] = None, le decimos a Python que ignore el módulo C-optimizado. Luego recargamos el módulo que causa la importación desde_datetimeque falle . Ahora las definiciones de Python puro permanecen y se pueden parchear normalmente.Si estas usando Pytest , incluya el fragmento de arriba en conftest.py y puede parchear
datetimeobjetos normalmente.fuente