测试时间敏感功能的利器:深入理解 pytest-freezegun

2779 篇文章 4 订阅
2619 篇文章 14 订阅

【5月1号开始准备软件测试面试】逼自己7天刷完这些面试题,轻松能上岸!(99%会被问到)

当编写测试时,有时需要模拟时间的流逝来测试与时间相关的功能。那如何解决该问题呢?带着疑问一起看。

pytest-freezegun是啥?

先抛出答案,使用这个插件可以轻松解决问题。

pytest-freezegun是一个非常有用的工具,它可以帮助我们在测试中冻结时间。这个插件随时可以变化当前系统时间,freezer可以冰冻时间,freezer.move_to可以改变时间,解决验证某一时间点的代码触发,或未来时间的代码变化问题。

安装 pytest-freezegun

首先,我们需要安装pytest-freezegun。

pip install pytest-freezegun

使用 pytest-freezegun

方法一:使用mark标记

pytest-freezegun允许我们在测试中冻结时间,以便于测试与时间相关的功能。它通过在测试函数上应用装饰器来实现这一点。下面是一个简单的示例:

import datetime
import pytest
​
​
@pytest.mark.freeze_time("2023-11-15")
def test_current_date():
    current_date = datetime.datetime.now()
    assert current_date == datetime.datetime(2023, 11, 15)

在上述示例中,我们使用@pytest.mark.freeze_time("2023-11-15")冻结在指定的时间点("2023-11-15"),而实际上当前时间是"2023-11-16"。在冻结时间期间,datetime.datetime.now()将始终返回指定的时间,这样我们就可以测试基于时间的逻辑。

执行这条用例,你会发现是通过的。

方法二:使用freezer fixture

import datetime
​
​
def test_current_date(freezer):
    current_date = datetime.datetime.now()
    freezer.move_to("2013-11-15")
    late = datetime.datetime.now()
    assert current_date == late

执行结果如下:

assert FakeDatetime(2023, 11, 16, 9, 20, 22, 606530) == FakeDatetime(2013, 11, 15, 0, 0) 

代码中,我们使用freezer.move_to来改变时间。

模拟时间的流逝

除了在特定时间点冻结时间外,pytest-freezegun还允许我们模拟时间的流逝。我们可以通过向@freeze_time装饰器传递一个字符串参数来指定时间的增量。下面是一个示例:

import datetime
import pytest
​
@pytest.mark.freeze_time("2023-11-15")
def test_current_date():
    current_date = datetime.datetime.now()
    new_date = current_date + datetime.timedelta(days=5)
    assert new_date == datetime.datetime(2023, 11, 20)

在上述示例中,我们使用datetime.timedelta类来表示时间的增量。通过将增量传递给datetime.timedelta,我们可以模拟时间的流逝。

运行原理

pytest-freezegun是一个Pytest插件,它基于freezegun库实现了对时间冻结的支持。

pytest-freezegun插件通过使用Pytest的fixture机制,为测试函数提供了方便的时间冻结功能。下面是pytest-freezegun实现原理的简要说明:

  1. pytest-freezegun定义了一个名为freezer的自定义fixture。这个fixture使用@pytest.fixture装饰器进行标记。
  2. 在fixture的实现中,pytest-freezegun使用freezegun库的freeze_time函数创建一个时间冻结器对象。并通过调用start方法开始冻结时间。
  3. 冻结后的时间对象被返回给测试函数,测试函数可以使用这个对象来模拟和控制时间的流逝。
  4. 当测试函数执行完毕后,pytest会自动清理fixture,并调用冻结器对象的stop方法停止时间冻结。

通过以上步骤,pytest-freezegun插件实现了Pytest中对时间冻结的支持。

看看源码

@pytest.fixture(name=FIXTURE_NAME)
def freezer_fixture(request):
    """
    Freeze time and make it available to the test
    """
    args = []
    kwargs = {}
    ignore = []
​
    # If we've got a marker, use the arguments provided there
    marker = get_closest_marker(request.node, MARKER_NAME)
    if marker:
        ignore = marker.kwargs.pop('ignore', [])
        args = marker.args
        kwargs = marker.kwargs
​
    # Always want to ignore _pytest
    ignore.append('_pytest.terminal')
    ignore.append('_pytest.runner')
​
    # Freeze time around the test
    freezer = freeze_time(*args, ignore=ignore, **kwargs)
    frozen_time = freezer.start()
    yield frozen_time
    freezer.stop()
​

解释一下代码的作用:

首先,通过检查测试函数上是否有特定标记(MARKER_NAME)来判断是否应用了时间冻结。如果有标记,则从标记中获取参数,包括忽略的模块列表(ignore)、位置参数和关键字参数。

接下来,将一些固定的模块(例如_pytest.terminal_pytest.runner)添加到忽略列表中,以确保这些模块不会受到时间冻结的影响。

然后,使用freeze_time函数创建一个时间冻结器对象(freezer),并调用其start方法开始冻结时间。冻结后的时间对象(frozen_time)被返回给测试函数使用。

在测试函数执行完毕后,使用yield语句将冻结后的时间对象返回给测试函数。这样,测试函数就可以在其运行期间使用冻结后的时间对象。

最后,使用stop方法停止时间冻结,以便时间可以继续流动。

最后

使用pytest-freezegun,我们可以轻松地模拟时间,以便测试与时间相关的功能。通过冻结时间或模拟时间的流逝,我们可以编写准确、可靠的时间相关的测试。

行动吧,在路上总比一直观望的要好,未来的你肯定会感谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入群: 759968159,里面有各种测试开发资料和技术可以一起交流哦。

最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】

​​​软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值