gpt4 book ai didi

Python 数据类 : Mocking the default factory in a frozen Dataclass

转载 作者:行者123 更新时间:2023-12-04 02:37:01 24 4
gpt4 key购买 nike

我试图在我的单元测试中使用 freezegun 来修补数据类中的一个字段,该字段设置为对象初始化时的当前日期。我想这个问题与任何尝试修补一个在 freezegun 之外用作 default_factory 的函数有关。数据类被卡住,因此它是不可变的。

例如,如果我的数据类是:

@dataclass(frozen=True)
class MyClass:
name: str
timestamp: datetime.datetime = field(init=False, default_factory=datetime.datetime.now)

当我用 freezegun 修补 datetime 时,它​​对 MyClass 中时间戳的初始化没有影响(它仍然将时间戳设置为单元测试中 now() 返回的当前日期,导致测试失败)。

我假设它与在补丁到位之前加载默认工厂和模块有关。我尝试修补日期时间,然后使用 importlib.reload 重新加载模块但没有运气。

我目前的解决方案是:
@dataclass(frozen=True)
class MyClass:
name: str
timestamp: datetime.datetime = field(init=False)

def __post_init__(self):
object.__setattr__(self, "timestamp", datetime.datetime.now())

哪个有效。

不过,理想情况下,我想要一个非侵入性的解决方案,不需要我更改生产代码来启用我的单元测试。

最佳答案

你是对的,数据类创建过程在这里做了一些奇怪的事情,这导致了你当前的问题。它在类创建期间绑定(bind)工厂函数,这意味着它在 freezegun 有机会修补它之前持有代码的引用。

这是一个没有遇到相同问题的数据类的示例:

from datetime import datetime
from freezegun import freeze_time

class Foo:
# looks up the function at class creation time
now_func = datetime.now

def __init__(self):
# asks datetime for a reference at instance creation time
self.timestamp_a = datetime.now()
# uses an old reference we couldn't patch
self.timestamp_b = Foo.now_func()


with freeze_time(datetime(2020, 1, 1)):
foo = Foo()
assert foo.timestamp_a == datetime(2020, 1, 1) # works
assert foo.timestamp_b == datetime(2020, 1, 1) # raises an AssertionError

至于怎么解决,理论上可以破解 MyClass.__init__.__closure__ 在您的测试期间切换功能,但这有点疯狂。

仍然比覆盖 timestamp 好一点的东西在 __post_init__可能只是用 lambda 委托(delegate)函数调用,以便名称查找延迟到实例化时间:

timestamp: datetime = field(init=False, default_factory=lambda: datetime.now())

或者您可以开始使用不同的日期时间库,例如 pendulum,它支持卡住时间 out of the box . FWIW,这就是我最终要做的。

关于Python 数据类 : Mocking the default factory in a frozen Dataclass,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61257658/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com