dennismonsewicz
dennismonsewicz

Reputation: 25542

Python: Mocking DateTime Issues

Here is my Python method:

for time in (timedelta(hours=3), timedelta(minutes=30)):

    delay = (datetime.now() + time).strftime('%Y-%m-%dT%H:%M:%S')
    payload = json.dumps({
        "channels": [
            "accountID-{acct_id}".format(acct_id=account_id)
        ],
        "push_time": delay,
        "data": {
            "alert": "Test Push",
            "m": "12345"
        },
    })

    try:
        requests.post(
            "https://api.parse.com/1/push",
            data=payload,
            headers={
                "X-Parse-Application-Id": settings.PARSE_APPLICATION_ID,
                "X-Parse-REST-API-Key": settings.PARSE_REST_API_KEY,
                "Content-Type": "application/json"
            }
        )
    except requests.exceptions.RequestException as e:
        logging.getLogger().setLevel(logging.ERROR)

Here is my test:

@patch("requests.post")
def test_send_push_notifications_to_parse(self, post_mock):
    post_mock.return_value = {"status": 200}
    mailing = Mock()
    mailing.name = "Foo Name"
    mailing.account_id = 12345
    mailing.mailing_id = 45

    payload = json.dumps({
        "channels": [
            "accountID-12345"
        ],
        "push_time": "2014-03-04T15:00:00",
        "data": {
            "alert": "Test Push",
            "m": "12345"
        },
    })

    send_push_notification_to_parse(mailing.account_id, mailing.mailing_id, mailing.name)

    post_mock.assert_called_with(
        "https://api.parse.com/1/push",
        data=payload,
        headers={
            "X-Parse-Application-Id": settings.PARSE_APPLICATION_ID,
            "X-Parse-REST-API-Key": settings.PARSE_REST_API_KEY,
            "Content-Type": "application/json"
        }
    )

The test fails because the POST request is inside of a loop where the datetimeobject changes. How can I patch the datetime object to make my test pass?

Upvotes: 1

Views: 3062

Answers (2)

Swapnil Sawant
Swapnil Sawant

Reputation: 620

Anyone stumbling on this old question like me can use freezegun that Lets your Python tests travel through time(like Interstellar:))

Upvotes: 0

Martijn Pieters
Martijn Pieters

Reputation: 1121914

Just mock datetime in your module:

@patch("your.module.datetime")
@patch("requests.post")
def test_send_push_notifications_to_parse(self, post_mock, dt_mock):
    # set datetime.now() to a fixed value
    dt_mock.now.return_value = datetime.datetime(2013, 2, 1, 10, 9, 8)

You bound datetime in your module with an import, and the above @patch decorator will replace that object with a mock.

If you need to test against multiple values, you can set the dt_mock.now.side_effect attribute instead; a list will cause the mock to return values one by one from that list on sequential calls, a method lets you produce a new value each time datetime.now() is called as needed.

Upvotes: 3

Related Questions