Alguém pode me dizer por que isso não está funcionando?
>>> 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)
Talvez alguém possa sugerir uma maneira melhor?
mock
biblioteca: voidspace.org.uk/python/mock/examples.html#partial-mockingRespostas:
Há alguns problemas.
Primeiro de tudo, a maneira como você está usando
mock.patch
não é muito correta. Quando usado como decorador, ele substitui a função / classe fornecida (neste casodatetime.date.today
) por umMock
objeto apenas dentro da função decorada . Portanto, somente dentro de vocêtoday()
haverádatetime.date.today
uma função diferente, que não parece ser o que você deseja.O que você realmente quer parece mais com isso:
Infelizmente, isso não vai funcionar:
Isso falha porque os tipos internos do Python são imutáveis - consulte esta resposta para obter mais detalhes.
Nesse caso, eu subclasseia datetime.date e criaria a função correta:
E agora você pode fazer:
fonte
datetime
instância para o valor original? comdeepcoppy
?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))))
.Outra opção é usar https://github.com/spulec/freezegun/
Instale-o:
E use-o:
Também afeta outras chamadas de data e hora em chamadas de método de outros módulos:
other_module.py:
main.py:
E finalmente:
fonte
Quanto vale a pena, os documentos do Mock falam sobre datetime.date.today especificamente, e é possível fazer isso sem a necessidade de criar uma classe fictícia:
https://docs.python.org/3/library/unittest.mock-examples.html#partial-mocking
fonte
from datetime import date
então é o nome do módulo ondefrom datetime import date
ea chamada paradate.today()
aparecerAcho que cheguei um pouco tarde para isso, mas acho que o principal problema aqui é que você está corrigindo o datetime.date.today diretamente e, de acordo com a documentação, isso está errado.
Você deve corrigir a referência importada no arquivo em que a função testada está, por exemplo.
Digamos que você tenha um arquivo functions.py no qual você tenha o seguinte:
então, no seu teste, você deve ter algo parecido com isto
Espero que isso ajude um pouco.
fonte
NameError: name 'datetime' is not defined
). De onde vem adatetime.strptime
referênciaMock(return_value=...)
se você não está importandodatetime
no seu arquivo de teste? ATUALIZAÇÃO: Tudo bem, eu apenas fui em frente e importei odatetime
módulo no arquivo de teste. Eu pensei que o truque era como você está escondendo adatetime
referência do arquivo de teste.import datetime
oufrom datetime import strptime
? se você estivesse fazendo o primeiro, teria que zombardatetime
e fazermocked_datetime.strptime.return_value = whatever
, é o posterior, teria que zombar diretamente da referência de strptime no arquivo em que o método testado mora.Mock(return_value=datetime...)
funcione.Para adicionar à solução de Daniel G :
Isso cria uma classe que, quando instanciada, retornará um objeto datetime.date normal, mas que também poderá ser alterado.
fonte
date
/datetime
si mesma, ela usa a variável globalmente disponível, então não deve haver nenhum problema: dpaste.com/790310Eu enfrentei a mesma situação alguns dias atrás, e minha solução foi definir uma função no módulo para testar e apenas zombar disso:
Hoje eu descobri o FreezeGun e parece cobrir esse caso lindamente
fonte
A maneira mais fácil para mim é fazer isso:
CUIDADO para esta solução: todas as funcionalidades da
datetime module
partir dotarget_module
irão parar de funcionar.fonte
datetime_mock.now = Mock(return_value=datetime(1999, 1, 1)
pode até ser reduzida paradatetime_mock.now.return_value = datetime(1999, 1, 1)
. Em vez de iniciar o patchstart()
, considere usar owith patch(...):
gerenciador de contexto para garantir que eledatetime
se comporte regularmente (desmembrado) novamente quando o teste terminar.datetime.datetime.now()
desmotivado ^^?datetime module
dotarget_module
vai parar de trabalhar.Você pode usar a seguinte abordagem, com base na solução de Daniel G. Este tem a vantagem de não quebrar a verificação de tipo
isinstance(d, datetime.date)
.Basicamente, substituímos a
datetime.date
classe baseada em C por nossa própria subclasse python, que produzdatetime.date
instâncias originais e responde aisinstance()
consultas exatamente como nativasdatetime.date
.Use-o como gerenciador de contexto em seus testes:
Abordagem semelhante pode ser usada para zombar da
datetime.datetime.now()
função.fonte
__instancecheck__
métodoDe um modo geral, você teria
datetime
ou talvezdatetime.date
importado para um módulo em algum lugar. Uma maneira mais eficaz de zombar do método seria corrigi-lo no módulo que o está importando. Exemplo:a.py
Em seguida, para o seu teste, o próprio objeto simulado seria passado como argumento para o método de teste. Você configuraria a simulação com o valor do resultado desejado e, em seguida, chamaria seu método em teste. Então você afirma que seu método fez o que deseja.
Uma palavra de alerta. É certamente possível exagerar na zombaria. Quando você o faz, torna seus testes mais longos, mais difíceis de entender e impossíveis de manter. Antes de zombar de um método tão simples quanto
datetime.date.today
, pergunte a si mesmo se você realmente precisa zombar dele. Se o seu teste for curto e direto e funcionar bem sem zombar da função, você pode estar apenas olhando para um detalhe interno do código que está testando, em vez de um objeto que você precisa zombar.fonte
Aqui está outra maneira de zombar,
datetime.date.today()
com um bônus adicional, de que o restante dasdatetime
funções continua funcionando, pois o objeto de zombaria está configurado para envolver odatetime
módulo original :Observe o
wraps=datetime
argumento paramock.patch()
- quando elefoo_module
usar outrasdatetime
funções além delasdate.today()
, serão encaminhadas para odatetime
módulo empacotado original .fonte
Várias soluções são discutidas em http://blog.xelnor.net/python-mocking-datetime/ . Em suma:
Objeto simulado - Simples e eficiente, mas quebra as verificações isinstance ():
Mock class
Use como:
fonte
Talvez você possa usar o seu próprio método "today ()" que irá corrigir quando necessário. Exemplo com zombaria de utcnow () pode ser encontrado aqui: https://bitbucket.org/k_bx/blog/src/tip/source/en_posts/2012-07-13-double-call-hack.rst?at=default
fonte
Eu implementei o método @ user3016183 usando um decorador personalizado:
Eu pensei que isso poderia ajudar alguém um dia ...
fonte
É possível simular funções do
datetime
módulo sem adicionarside_effects
fonte
Para aqueles que usam pytest com mocker, aqui está como eu zombei, o
datetime.datetime.now()
que é muito semelhante à pergunta original.Essencialmente, a simulação deve ser configurada para retornar a data especificada. Você não pode corrigir o objeto do datetime diretamente.
fonte
Eu fiz este trabalho, importando
datetime
comorealdatetime
e substituindo os métodos que eu precisava na simulação com os métodos reais:fonte
Você pode zombar
datetime
usando isso:No módulo
sources.py
:No seu
tests.py
:fonte
sources
no seu decorador de patches?CPython realmente implementa o módulo de data e hora usando tanto um puro-Python Lib / datetime.py e um optimizado-C módulos / _datetimemodule.c . A versão otimizada para C não pode ser corrigida, mas a versão pura em Python pode.
Na parte inferior da implementação do Python puro em Lib / datetime.py está este código:
Esse código importa todas as definições otimizadas para C e substitui efetivamente todas as definições de Python puro. Podemos forçar o CPython a usar a implementação em Python puro do módulo datetime, fazendo:
Ao definir
sys.modules["_datetime"] = None
, dizemos ao Python para ignorar o módulo otimizado para C. Em seguida, recarregamos o módulo que causa a importação de_datetime
falha . Agora, as definições de Python puro permanecem e podem ser corrigidas normalmente.Se você estiver usando o Pytest , inclua o trecho acima em conftest.py e poderá corrigir os
datetime
objetos normalmente.fonte