태그 보관물: mocking

mocking

datetime.date.today ()를 조롱하려고 시도했지만 작동하지 않습니다. 말해 줄 수 있습니까? >>> import

왜 이것이 작동하지 않는지 말해 줄 수 있습니까?

>>> 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.patch옳지 않습니다. 데코레이터로 사용될 때 주어진 함수 / 클래스 (이 경우 datetime.date.today) 는 데코 레이팅 된 함수 내에서만Mock 객체로 대체합니다 . 그래서, 단지 내 것이다 당신이 원하는 것처럼 보이지 않는 다른 기능을합니다.today()datetime.date.today

정말로 원하는 것은 다음과 같습니다.

@mock.patch('datetime.date.today')
def test():
    datetime.date.today.return_value = date(2010, 1, 1)
    print datetime.date.today()

불행히도 이것은 작동하지 않습니다.

>>> test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "build/bdist.macosx-10.6-universal/egg/mock.py", line 557, in patched
  File "build/bdist.macosx-10.6-universal/egg/mock.py", line 620, in __enter__
TypeError: can't set attributes of built-in/extension type 'datetime.date'

파이썬 내장 타입은 불변이기 때문에 실패합니다- 자세한 내용 은 이 답변 을 참조하십시오.

이 경우 datetime.date를 직접 서브 클래스하고 올바른 함수를 만듭니다.

import datetime
class NewDate(datetime.date):
    @classmethod
    def today(cls):
        return cls(2010, 1, 1)
datetime.date = NewDate

그리고 지금 당신은 할 수 있습니다 :

>>> datetime.date.today()
NewDate(2010, 1, 1)

답변

또 다른 옵션은 https://github.com/spulec/freezegun/ 을 사용하는 것입니다

설치하십시오 :

pip install freezegun

그리고 그것을 사용하십시오 :

from freezegun import freeze_time

@freeze_time("2012-01-01")
def test_something():

    from datetime import datetime
    print(datetime.now()) #  2012-01-01 00:00:00

    from datetime import date
    print(date.today()) #  2012-01-01

또한 다른 모듈의 메소드 호출에서 다른 날짜 및 시간 호출에 영향을줍니다.

other_module.py :

from datetime import datetime

def other_method():
    print(datetime.now())    

main.py :

from freezegun import freeze_time

@freeze_time("2012-01-01")
def test_something():

    import other_module
    other_module.other_method()

그리고 마지막으로:

$ python main.py
# 2012-01-01

답변

가치있는 것을 위해 Mock 문서는 datetime.date.today에 대해 구체적으로 이야기하며 더미 클래스를 만들지 않고도이 작업을 수행 할 수 있습니다.

https://docs.python.org/3/library/unittest.mock-examples.html#partial-mocking

>>> from datetime import date
>>> with patch('mymodule.date') as mock_date:
...     mock_date.today.return_value = date(2010, 10, 8)
...     mock_date.side_effect = lambda *args, **kw: date(*args, **kw)
...
...     assert mymodule.date.today() == date(2010, 10, 8)
...     assert mymodule.date(2009, 6, 8) == date(2009, 6, 8)
...

답변

나는 이것에 대해 조금 늦게 온 것 같지만 여기서 가장 큰 문제는 datetime.date.today를 직접 패치하고 문서에 따르면 이것이 잘못되었다는 것입니다.

예를 들어 테스트 된 기능이있는 파일로 가져온 참조를 패치해야합니다.

다음과 같은 functions.py 파일이 있다고 가정 해 봅시다.

import datetime

def get_today():
    return datetime.date.today()

그런 다음 테스트에서 다음과 같은 것이 있어야합니다

import datetime
import unittest

from functions import get_today
from mock import patch, Mock

class GetTodayTest(unittest.TestCase):

    @patch('functions.datetime')
    def test_get_today(self, datetime_mock):
        datetime_mock.date.today = Mock(return_value=datetime.strptime('Jun 1 2005', '%b %d %Y'))
        value = get_today()
        # then assert your thing...

이것이 약간 도움이되기를 바랍니다.


답변

에 추가하려면 다니엘 G의 솔루션 :

from datetime import date

class FakeDate(date):
    "A manipulable date replacement"
    def __new__(cls, *args, **kwargs):
        return date.__new__(date, *args, **kwargs)

인스턴스화하면 일반 datetime.date 객체를 반환하지만 변경할 수있는 클래스가 만들어집니다.

@mock.patch('datetime.date', FakeDate)
def test():
    from datetime import date
    FakeDate.today = classmethod(lambda cls: date(2010, 1, 1))
    return date.today()

test() # datetime.date(2010, 1, 1)

답변

나는 며칠 전에 같은 상황에 처해 있었고 내 솔루션은 모듈에서 함수를 정의하여 테스트하고 조롱하는 것이 었습니다.

def get_date_now():
    return datetime.datetime.now()

오늘 저는 FreezeGun 에 대해 알아 냈습니다 .이 사건을 아름답게 다루는 것 같습니다.

from freezegun import freeze_time
import datetime
import unittest


@freeze_time("2012-01-14")
def test():
    assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)

답변

가장 쉬운 방법은 다음과 같습니다.

import datetime
from unittest.mock import Mock, patch

def test():
    datetime_mock = Mock(wraps=datetime.datetime)
    datetime_mock.now.return_value = datetime.datetime(1999, 1, 1)
    with patch('datetime.datetime', new=datetime_mock):
        assert datetime.datetime.now() == datetime.datetime(1999, 1, 1)

이 솔루션에 대한주의 : 모든 기능 datetime module로부터 target_module중지됩니다 작업.