¿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?
mock
biblioteca: voidspace.org.uk/python/mock/examples.html#partial-mockingRespuestas:
Hay algunos problemas
En primer lugar, la forma en que está utilizando
mock.patch
no es del todo correcta. Cuando se usa como decorador, reemplaza la función / clase dada (en este casodatetime.date.today
) con unMock
objeto solo dentro de la función decorada . Entonces, solo dentro de ustedtoday()
habrádatetime.date.today
una 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
datetime
instancia 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 date
entonces es el nombre del módulo donde aparecefrom datetime import date
y 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.strptime
referenciaMock(return_value=...)
si no está importandodatetime
en su archivo de prueba? ACTUALIZACIÓN: Está bien, simplemente seguí adelante e importé eldatetime
módulo en el archivo de prueba. Pensé que el truco era cómo ocultas ladatetime
referencia del archivo de prueba.import datetime
ofrom datetime import strptime
? si estuviera haciendo el primero, tendría que burlarsedatetime
y 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
/datetime
utiliza, 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 module
de latarget_module
dejará 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 sedatetime
comporta regularmente (sin desbloquear) nuevamente cuando finaliza la prueba.datetime.datetime.now()
desbloquear ^^?datetime module
desde eltarget_module
dejará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.date
clase basada en C con nuestra propia subclase de Python, que producedatetime.date
instancias 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
datetime
o quizásdatetime.date
importado 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 dedatetime
funciones continúan funcionando, ya que el objeto simulado está configurado para envolver eldatetime
módulo original :Tenga en cuenta el
wraps=datetime
argumento demock.patch()
: cuandofoo_module
utiliza otrasdatetime
funciones además dedate.today()
que se enviarán aldatetime
mó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
datetime
módulo sin agregarside_effects
fuente
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
datetime
comorealdatetime
y la sustitución de los métodos que se necesitan en la maqueta con los métodos reales:fuente
Puedes burlarte de
datetime
esto:En el modulo
sources.py
:En su
tests.py
:fuente
sources
en 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_datetime
que 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
datetime
objetos normalmente.fuente