【问题标题】:Python test using mock with datetime.utcnow()使用带有 datetime.utcnow() 的模拟进行 Python 测试
【发布时间】:2019-08-27 09:27:09
【问题描述】:

我的 utils.py 中有以下功能,基本上计算从 1970 年到当前时间的秒数:

import datetime

def get_utc_timestamp():
    d = datetime.datetime.utcnow()
    epoch = datetime.datetime(1970, 1, 1)
    t = (d - epoch).total_seconds()

    return t

我想在该函数上运行一个测试用例,但它取决于时间,所以我寻找解决方案并在 SO link 上偶然发现了这个问题,我试图在我的 test_utils.py 中应用它:

import unittest
from utils import *
from unittest import mock
import datetime

class TestUtils(unittest.TestCase):

    @mock.patch('utils.datetime.datetime')
    def test_get_utc_timestamp(self, mock_dt):
        mock_dt.utcnow = mock.Mock(return_value = datetime.datetime(2019, 8, 27, 8, 52, 12, 703618))
        result = get_utc_timestamp()
        self.assertEqual(result, 1566895932.703618)

if __name__ == '__main__':
    unittest.main()

我在控制台中测试了它的结果:

d = datetime.datetime(2019, 8, 27, 8, 52, 12, 703618)
epoch = datetime.datetime(1970, 1, 1)
t = (d - epoch).total_seconds()

return t

它返回了

1566895932.703618

但是当我运行测试时,我得到了 AssertionError:

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/unittest/mock.py", line 1179, in patched
    return func(*args, **keywargs)
  File "/app/tests/test_utils.py", line 15, in test_get_utc_timestamp
    self.assertEqual(result, 1566895932.703618)
AssertionError: <MagicMock name='datetime().__sub__().total_seconds()' id='140475857850040'> != 1566895932.703618

我做错了什么?

任何帮助将不胜感激!

编辑:

感谢 ipaleka 对发生的事情的解释,因为我无法使用 mock 更改内置的 python 类,所以我需要创建一个 utcnow() 的自定义类来返回 test_utils.py 中的自定义时间:

class NewDate(datetime.datetime):
    @classmethod
    def utcnow(cls):
        return cls(2019, 8, 27, 8, 52, 12, 703618)

datetime.datetime = NewDate

并将测试功能更改为:

def test_get_utc_timestamp(self):
    result = get_utc_timestamp()
    self.assertEqual(result, 1566895932.703618)

【问题讨论】:

  • 您可以尝试将@mock.patch('utils.datetime.datetime') 替换为@mock.patch('datetime.datetime') 吗?您可能正在“修补错误的名称”(请参阅​​docs.python.org/3/library/unittest.mock.html#where-to-patch
  • 我替换了它,它仍然返回 AssertionError,我的包含 test_utils.py 的测试文件夹与 utils.py 处于同一顶层

标签: python datetime mocking python-unittest


【解决方案1】:

您没有做与引用的 SO 答案相关的任何错误,但该示例仅使用 utcnow 函数,而您同时使用 utcnowdatetime(用于创建 epoch 变量)。

当您修补模块时,每次调用子模块、方法或其函数都会创建一个 MagicMock。当您致电epoch = datetime.datetime(1970, 1, 1) 时,就会发生这种情况。所以基本上你是在比较 MagicMock 和 float。

您应该同时修补它们或只修补utcnow

@mock.patch('utils.datetime.datetime.utcnow')
def test_get_utc_timestamp(self, mock_dt):
    mock_dt.return_value = datetime.datetime(2019, 8, 27, 8, 52, 12, 703618)
    result = get_utc_timestamp()
    self.assertEqual(result, 1566895932.703618)

【讨论】:

  • 它似乎无法设置python内置'datetime.datetime'类型错误的值:无法设置内置/扩展类型'datetime.datetime'的属性
  • nvm 我只是用自定义 return 替换基本 datetime.datetime.utc 类,在描述中进行了编辑。感谢您的解释!
猜你喜欢
  • 2017-10-03
  • 2021-05-06
  • 1970-01-01
  • 2018-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-05
相关资源
最近更新 更多