Может кто-нибудь сказать мне, почему это не работает?
>>> 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)
Возможно, кто-то может предложить лучший способ?
mock
библиотеки: voidspace.org.uk/python/mock/examples.html#partial-mockingОтветы:
Есть несколько проблем.
Во-первых, то, как вы используете
mock.patch
, не совсем правильно. При использовании в качестве декоратора он заменяет данную функцию / класс (в данном случаеdatetime.date.today
)Mock
объектом только внутри декорированной функции . Таким образом, только внутри васtoday()
будетdatetime.date.today
другая функция, которая не соответствует вашим ожиданиям.То, что вы действительно хотите, похоже, выглядит примерно так:
К сожалению, это не сработает:
Это терпит неудачу, потому что встроенные типы Python являются неизменяемыми - см. Этот ответ для более подробной информации.
В этом случае я бы создал подкласс datetime.date и создал бы правильную функцию:
И теперь вы можете сделать:
источник
datetime
экземпляр к его первоначальному значению? сdeepcoppy
?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))))
.Другой вариант - использовать https://github.com/spulec/freezegun/.
Установите это:
И использовать это:
Это также влияет на другие вызовы datetime в вызовах методов из других модулей:
other_module.py:
main.py:
И наконец:
источник
Что бы это ни стоило, в документации Mock конкретно говорится о datetime.date.today, и это можно сделать без необходимости создания фиктивного класса:
https://docs.python.org/3/library/unittest.mock-examples.html#partial-mocking
источник
from datetime import date
то имя модуля , в которомfrom datetime import date
и вызовdate.today()
появляетсяДумаю, я немного опоздал на это, но я думаю, что главная проблема здесь в том, что вы исправляете datetime.date.today напрямую, и, согласно документации, это неправильно.
Вы должны исправить ссылку, импортированную в файл, где находится, например, проверенная функция.
Допустим, у вас есть файл functions.py, в котором есть следующее:
тогда, в вашем тесте, вы должны иметь что-то вроде этого
Надеюсь, это поможет немного.
источник
NameError: name 'datetime' is not defined
). Откуда беретсяdatetime.strptime
ссылка,Mock(return_value=...)
если вы не импортируетеdatetime
в свой тестовый файл? ОБНОВЛЕНИЕ: Все в порядке, я просто пошел вперед и импортировалdatetime
модуль в тестовый файл. Я думал, что уловка была в том, что вы скрываетеdatetime
ссылку из тестового файла.import datetime
илиfrom datetime import strptime
? Если бы вы делали первый, вам нужно было бы смоделироватьdatetime
и сделатьmocked_datetime.strptime.return_value = whatever
, а потом - вам бы пришлось напрямую смоделировать ссылку strptime в файле, где живет тестируемый метод.Mock(return_value=datetime...)
работы.Чтобы добавить к решению Даниеля G :
Это создает класс, который при создании экземпляра будет возвращать обычный объект datetime.date, но который также может быть изменен.
источник
date
/datetime
сам, он использует глобально доступную переменную, поэтому проблем не должно быть: dpaste.com/790310Я столкнулся с такой же ситуацией пару дней назад, и мое решение состояло в том, чтобы определить функцию в модуле для тестирования и просто посмеяться над этим:
Сегодня я узнал о FreezeGun , и, кажется, он прекрасно освещает этот случай
источник
Самый простой способ для меня это сделать:
ВНИМАНИЕ для этого решения: все функциональные возможности
datetime module
отtarget_module
перестанут работать.источник
datetime_mock.now = Mock(return_value=datetime(1999, 1, 1)
может быть даже сокращена доdatetime_mock.now.return_value = datetime(1999, 1, 1)
. Вместо того, чтобы начинать патч сstart()
, рассмотрите возможность использованияwith patch(...):
диспетчера контекста, чтобы убедиться, чтоdatetime
он снова будет работать регулярно (без проверки), когда ваш тест закончится.datetime.datetime.now()
unmocked ^^?datetime module
возможностиtarget_module
перестают работать.Вы можете использовать следующий подход, основанный на решении Daniel G. У этого есть преимущество, не нарушая проверку типа с
isinstance(d, datetime.date)
.По сути, мы заменим
datetime.date
класс на основе C нашим собственным подклассом python, который создает оригинальныеdatetime.date
экземпляры и отвечает наisinstance()
запросы точно так же, как и собственныеdatetime.date
.Используйте его как менеджер контекста в своих тестах:
Подобный подход может быть использован для макетирования
datetime.datetime.now()
функции.источник
__instancecheck__
метода.Вообще говоря, вы могли бы
datetime
или, возможно,datetime.date
импортировать в модуль где-нибудь. Более эффективный способ насмешки над этим методом - установить его на модуль, который его импортирует. Пример:a.py
Затем для вашего теста сам фиктивный объект будет передан в качестве аргумента методу теста. Вы должны настроить макет с желаемым значением результата, а затем вызвать тестируемый метод. Тогда вы бы утверждали, что ваш метод сделал то, что вы хотите.
Слово предупреждения. Безусловно, можно пойти за борт с насмешками. Когда вы это делаете, это делает ваши тесты более длинными, трудными для понимания и невозможными для обслуживания. Прежде чем издеваться над таким простым методом
datetime.date.today
, спросите себя, действительно ли вам нужно его издеваться. Если ваш тест является коротким и точным и работает нормально, без насмешки над функцией, вы можете просто смотреть на внутреннюю деталь кода, который вы тестируете, а не на объект, который вам нужно смоделировать.источник
Вот еще один способ смоделировать
datetime.date.today()
с дополнительным бонусом, что остальныеdatetime
функции продолжают работать, так как фиктивный объект настроен для обертывания исходногоdatetime
модуля:Обратите внимание на
wraps=datetime
аргументmock.patch()
- когдаfoo_module
используются другиеdatetime
функции, кроме того, чтоdate.today()
они будут перенаправлены в исходный упакованныйdatetime
модуль.источник
Несколько решений обсуждаются в http://blog.xelnor.net/python-mocking-datetime/ . В итоге:
Макет объекта - простой и эффективный, но нарушает проверку isinstance ():
Ложный класс
Использовать как:
источник
Возможно, вы могли бы использовать свой собственный метод today (), который вы будете исправлять там, где это необходимо. Пример с насмешкой utcnow () можно найти здесь: https://bitbucket.org/k_bx/blog/src/tip/source/en_posts/2012-07-13-double-call-hack.rst?at=default
источник
Я реализовал метод @ user3016183, используя собственный декоратор:
Я думал, что это может помочь кому-то однажды ...
источник
Можно макетировать функции из
datetime
модуля без добавленияside_effects
источник
Для тех из вас, кто использует pytest с mocker, вот как я высмеивал,
datetime.datetime.now()
что очень похоже на оригинальный вопрос.По сути, макет должен быть установлен, чтобы вернуть указанную дату. Вы не можете напрямую связать объект datetime.
источник
Я сделал эту работу за счет импорта ,
datetime
какrealdatetime
и замена методов я нуждался в издеваться с реальными методами:источник
Вы можете издеваться,
datetime
используя это:В модуле
sources.py
:В вашем
tests.py
:источник
sources
у тебя в патче-декораторе?CPython фактически реализует модуль datetime, используя как чистый Python Lib / datetime.py, так и C-оптимизированные модули / _datetimemodule.c . C-оптимизированная версия не может быть исправлена, но версия с чистым Python может.
В нижней части реализации чистого Python в Lib / datetime.py находится этот код:
Этот код импортирует все C-оптимизированные определения и эффективно заменяет все определения на чистом Python. Мы можем заставить CPython использовать чистую реализацию Python модуля datetime, выполнив:
Установив
sys.modules["_datetime"] = None
, мы говорим Python игнорировать C-оптимизированный модуль. Затем мы перезагружаем модуль, который вызывает_datetime
сбой импорта из . Теперь определения чистого Python остаются и могут быть исправлены как обычно.Если вы используете Pytest, включите приведенный выше фрагмент в conftest.py, и вы сможете исправлять
datetime
объекты обычным образом.источник