Python:模拟日期时间问题

1 投票
2 回答
2833 浏览
提问于 2025-04-17 21:18

这是我的Python方法:

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)

这是我的测试:

@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"
        }
    )

测试失败的原因是因为POST请求在一个循环里面,而这个循环中的datetime对象在不断变化。请问我该如何修改datetime对象,才能让我的测试通过呢?

2 个回答

0

如果你和我一样偶然发现了这个老问题,可以试试 freezegun 这个工具,它可以让你的Python测试“穿越时间”(就像电影《星际穿越》一样:)

3

只需在你的模块中模拟 datetime

@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)

你在模块中通过导入绑定了 datetime,而上面的 @patch 装饰器会把这个对象替换成一个模拟对象。

如果你需要测试多个值,可以设置 dt_mock.now.side_effect 属性;使用一个列表会让模拟对象在连续调用时一个一个地返回列表中的值,而使用一个方法则可以让你在每次调用 datetime.now() 时生成一个新的值。

撰写回答