【问题标题】:py.test: Mocking a datetime object that is constantly changingpy.test:模拟一个不断变化的日期时间对象
【发布时间】:2017-10-20 11:15:05
【问题描述】:

如果返回的日期时间对象不断变化,您如何模拟该对象?

例如,我有一些查询 api 的代码,获取一些时间序列数据并将其作为一系列日期时间对象返回。

所以查询的 api 的返回数据看起来像:

{
    'from_date': 1497881400000.0,
                'group_by': [],
                'message': '',
                'query': 'avg:system.load.norm.5{role:lb}',
                'res_type': 'time_series',
                'resp_version': 1,
                'series': [{'aggr': 'avg',
                                    'attributes': {},
                                    'display_name': 'system.load.norm.5',
                                    'end': 1497709799000,
                                    'expression': 'avg:system.load.norm.5{role:lb}',
                                    'interval': 1,
                                    'length': 60,
                                    'metric': 
                                    'avg:system.load.norm.5{role:lb}',
                                    'pointlist': [[1497881400000.0,
                                     0.06923198629355053], 
                                    [.. 60 more points]],
                                    'query_index': 0,
                                    'scope': 'role:lb',
                                    'start': 1497709742000,
                                    'unit': [None, None]}],
                'status': 'ok',
                'to_date': 1497709800000
}

我的代码就是这样做的:

from typing import NamedTuple

class SampleMetric(NamedTuple):
    query: str
    time: datetime.datetime
    value: int

pointlist = api_query['series'][0]['pointlist']
return [SampleMetric(query=metric,
                             time=datetime.datetime.fromtimestamp(
                                 point[0] / 1000),
                             value=point[1]) for point in pointlist]

在上述 api 数据的情况下,它看起来像这样:

[SampleMetric(query='avg:system.load.norm.5{role:lb}', time=datetime.datetime(2017, 10, 20, 11, 2), value=231.8605833053589),
 SampleMetric(query='avg:system.load.norm.5{role:lb}', time=datetime.datetime(2017, 10, 20, 11, 3), value=243.17432022094727),...]

所以我可以像上面的示例一样轻松创建一个返回字典的模拟 api 对象,但我真的很难模拟返回的不断变化的日期时间对象。

time=datetime.datetime(2017, 10, 20, 11, 2)

谁能给我任何关于如何做到这一点的想法吗?目前,我通过在返回数据中仅包含一个时间序列点并对时间值进行硬编码来解决此问题,但我觉得这并不是真正的测试,因为它应该返回 60 个结果。

忽略此示例中使用的实际值,我知道它们是错误的,但这仅用于说明目的,因为我正在努力解释我的意思。

【问题讨论】:

  • 如果你能给出一个你试图测试的简单代码的具体例子,并描述为什么测试很难编写,你会得到更多有用的答案。我猜了你的意思,但我不确定。

标签: python unit-testing mocking pytest


【解决方案1】:

我不确定您所说的“不断变化”到底是什么意思,所以我将猜测两个答案。

我的第一个猜测是,当结果取决于当前时间时,您想知道如何编写单元测试。这使得输出不断变化,因此很难编写测试。

为了解决这个问题,我要么将当前时间作为显式输入参数传递给我正在测试的代码,要么模拟datetime.now() 方法。这样,单元测试总是基于相同的时间计算,并且应该总是得到相同的结果。这也使得测试有趣的边缘情况变得更加容易,比如夏令时的变化。您可以为每个有趣的场景编写一个单独的测试用例,每个场景都有不同的“当前时间”。

我的第二个猜测是,您问的是如何为您的输入数据创建一组 60 个不同的日期时间值。我可能会为前几个条目计算几个有趣的值,然后使用for 循环或range() 表达式生成其余的值。

【讨论】:

    猜你喜欢
    • 2017-08-20
    • 2011-07-25
    • 1970-01-01
    • 2020-07-15
    • 1970-01-01
    • 2012-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多