Freezegun:Python 时间冻结单元测试
Freezegun 冻结测试中的时间:@freeze_time 装饰器、上下文管理器、tick 推进时间、时区测试。调度任务、过期逻辑、时间条件的测试从此稳定可复现。
本文依据官方文档整理,未执行运行验证或性能基准。代码片段展示局部用法,业务函数、数据和环境需按项目补齐;版本与配置以所引文档为准。
直接回答:Freezegun 让测试里的 datetime.now() 返回你指定的时刻——@freeze_time("2026-01-15") 装饰器或上下文管理器冻结时间,tick() 推进,auto_tick_seconds 在读取受支持的时间 API 时按设定步长递增。测定时任务、过期判断、时间窗口逻辑的必备工具。
基本用法
from freezegun import freeze_time
import datetime
@freeze_time("2026-01-15 09:30:00")
def test_日报生成():
assert get_report_date() == datetime.date(2026, 1, 15)
# 上下文管理器形态
def test_过期():
with freeze_time("2026-01-01"):
token = create_token(ttl_days=7)
with freeze_time("2026-01-09"):
assert token.is_expired()
时间推进
with freeze_time("2026-01-01 00:00") as frozen:
step1()
frozen.tick(delta=datetime.timedelta(hours=1)) # 推进 1 小时
step2()
# 或在读取时间时自动递增
with freeze_time("2026-01-01", auto_tick_seconds=10):
...
时区测试
@freeze_time("2026-01-15 12:00", tz_offset=8)
def test_北京时间(): ...
tz_offset 是固定偏移,不是 Asia/Shanghai 等具备历史规则的 IANA 时区;示例中 UTC 的 now 为12点,本地无时区 now 为20点。跨夏令时业务应使用带 ZoneInfo 的 aware datetime 验证。
常见问题(FAQ)
Q:能冻结 time.sleep 吗?
A:不会加速真实 time.sleep。tick 推进模拟时钟,auto_tick_seconds 是每次取时自动递增,不会让阻塞的 sleep 自动结束。异步测试冻结 monotonic 可能卡住事件循环,可按文档用 real_asyncio=True。
Q:对第三方库生效吗?
A:对它支持并补丁到的 Python 时间调用有效,但忽略列表、默认参数绑定、某些持有引用的容器及 C/外部进程时间调用可能不受影响,不能保证所有第三方库均被冻结。
Q:和 pytest 怎么配?
A:直接装饰测试函数即可;也有 pytest-freezegun 插件提供 fixture 风格。
官方参考
资料核对日期:2026-09-29。