如何通过pytest与__instancecheck__修复datetime.now补丁后的isinstance校验问题
问题解决:Mock datetime.now后isinstance校验失败
问题场景
在使用pytest测试Python项目时:
- 代码中用到了
datetime.datetime类、datetime.datetime.now()函数 - 存在
isinstance(time, datetime.datetime)的校验逻辑,其中time是未被Mock的真实DateTime对象 - 补丁
now()函数后,isinstance(time, datetime.datetime)返回False,打印type(time)显示为:<class 'test_Itinerarios.patch_datetime_now.<locals>.mydatetime'>
要求通过pytest与__instancecheck__实现正确校验,且不能引入其他测试库。
解决方案
问题核心:替换datetime.datetime为自定义子类mydatetime后,真实DateTime实例并非mydatetime的实例,导致isinstance校验失败。需通过**元类重写__instancecheck__**修正校验逻辑,具体代码如下:
import datetime import pytest Fake_time = datetime.datetime(2024, 3, 7, 18, 00) real_datetime_class = datetime.datetime # 获取datetime.datetime的原始元类 real_datetime_meta = type(datetime.datetime) @pytest.fixture def patch_datetime_now(monkeypatch): # 自定义元类,重写__instancecheck__ class MyDateTimeMeta(real_datetime_meta): def __instancecheck__(cls, obj): # 同时识别原始datetime实例和自定义mydatetime实例 return isinstance(obj, real_datetime_class) or super().__instancecheck__(obj) class mydatetime(datetime.datetime, metaclass=MyDateTimeMeta): @classmethod def now(cls): return Fake_time monkeypatch.setattr(datetime, 'datetime', mydatetime)
原理说明
__instancecheck__是元类的方法,负责处理isinstance(obj, cls)的校验逻辑- 自定义元类
MyDateTimeMeta继承自datetime.datetime的原始元类,重写__instancecheck__后,既会检查对象是否是原始datetime.datetime的实例,也保留了子类实例的正常校验逻辑 - 无论
time是原始DateTime对象还是Mock后的mydatetime对象,isinstance(time, datetime.datetime)都会返回True
内容的提问来源于stack exchange,提问作者Daniel Baquero
相关产品推荐
相关产品推荐

