如何指定默认为 AttributeError() 且没有显式赋值的 Python 模拟?
How to spec a Python mock which defaults to AttributeError() without explicit assignment?
我有一个与 Python unittest.mock.Mock
和 spec_set
功能相关的问题。
我的目标是创建一个具有以下功能的 Mock:
- 它有一个任意的规范 class 我在创建时决定。
- 我必须能够根据第 1 点的规范在 mock 上仅分配属性或方法
- Mock 必须在以下情况下引发 AttributeError:
- 我尝试分配一个不在规范中的属性
- 我调用或检索了一个 属性,它在
spec_set
中缺失,或者在 spec_set
中存在但根据上述点分配。
我想要的一些行为示例:
class MyClass:
property: int = 5
def func() -> int:
pass
# MySpecialMock is the Mock with the functionalities I am dreaming about :D
mock = MyMySpecialMock(spec_set=MyClass)
mock.not_existing # Raise AttributeError
mock.func() # Raise AttributeError
mock.func = lambda: "it works"
mock.func() # Returns "it works"
我尝试了多种解决方案,但都没有成功,或者没有明确地冗长。以下是一些示例:
- 使用
Mock(spec_set=...)
,但它不会在我调用未明确设置的特定属性时引发错误
- 使用
Mock(spec_set=...)
并使用具有异常副作用的函数显式覆盖每个属性,但它非常冗长,因为我必须重复所有属性...
我的目标是找到一种使 2 自动化的方法,但我没有干净的方法来做到这一点。你遇到过这样的问题,并解决了吗?
对于好奇的人,目标是能够增强单元测试的分离;我想确保我的模拟仅在我明确设置的方法上被调用,以避免奇怪和意外的副作用。
提前致谢!
spec_set
定义了一个 mock
对象,它与 class 相同,但是不允许对其进行任何更改,因为它定义了特殊的 __getattr__
和 __setattr__
。这意味着第一个测试(调用不存在的 attr)将按预期失败,但随后尝试设置 attr 也会失败:
from unitest import mock
class X:
pass
m = mock.Mock(spec_set=X)
m.func()
# __getattr__: AttributeError: Mock object has no attribute 'func'
m.func = lambda: "it works"
# __setattr__: AttributeError: Mock object has no attribute 'func'
相反,您可以使用 create_autospec()
复制现有函数,并向其添加 mock
函数,但不会影响 __setattr__
:
n = mock.create_autospec(X)
n.func()
# __getattr__: AttributeError: Mock object has no attribute 'func'
n.func = lambda: "it works"
n.func()
# 'it works'
我想我通过使用 dir
方法找到了我的问题的令人满意的答案。
要根据我上面列出的要求创建 Mock,执行以下操作应该就足够了:
def create_mock(spec: Any) -> Mock:
mock = Mock(spec_set=spec)
attributes_to_override = dir(spec)
for attr in filter(lambda name: not name.startswith("__"), attributes_to_override):
setattr(mock, attr, Mock(side_effect=AttributeError(f"{attr} not implemented")))
return mock
我有一个与 Python unittest.mock.Mock
和 spec_set
功能相关的问题。
我的目标是创建一个具有以下功能的 Mock:
- 它有一个任意的规范 class 我在创建时决定。
- 我必须能够根据第 1 点的规范在 mock 上仅分配属性或方法
- Mock 必须在以下情况下引发 AttributeError:
- 我尝试分配一个不在规范中的属性
- 我调用或检索了一个 属性,它在
spec_set
中缺失,或者在spec_set
中存在但根据上述点分配。
我想要的一些行为示例:
class MyClass:
property: int = 5
def func() -> int:
pass
# MySpecialMock is the Mock with the functionalities I am dreaming about :D
mock = MyMySpecialMock(spec_set=MyClass)
mock.not_existing # Raise AttributeError
mock.func() # Raise AttributeError
mock.func = lambda: "it works"
mock.func() # Returns "it works"
我尝试了多种解决方案,但都没有成功,或者没有明确地冗长。以下是一些示例:
- 使用
Mock(spec_set=...)
,但它不会在我调用未明确设置的特定属性时引发错误 - 使用
Mock(spec_set=...)
并使用具有异常副作用的函数显式覆盖每个属性,但它非常冗长,因为我必须重复所有属性...
我的目标是找到一种使 2 自动化的方法,但我没有干净的方法来做到这一点。你遇到过这样的问题,并解决了吗?
对于好奇的人,目标是能够增强单元测试的分离;我想确保我的模拟仅在我明确设置的方法上被调用,以避免奇怪和意外的副作用。
提前致谢!
spec_set
定义了一个 mock
对象,它与 class 相同,但是不允许对其进行任何更改,因为它定义了特殊的 __getattr__
和 __setattr__
。这意味着第一个测试(调用不存在的 attr)将按预期失败,但随后尝试设置 attr 也会失败:
from unitest import mock
class X:
pass
m = mock.Mock(spec_set=X)
m.func()
# __getattr__: AttributeError: Mock object has no attribute 'func'
m.func = lambda: "it works"
# __setattr__: AttributeError: Mock object has no attribute 'func'
相反,您可以使用 create_autospec()
复制现有函数,并向其添加 mock
函数,但不会影响 __setattr__
:
n = mock.create_autospec(X)
n.func()
# __getattr__: AttributeError: Mock object has no attribute 'func'
n.func = lambda: "it works"
n.func()
# 'it works'
我想我通过使用 dir
方法找到了我的问题的令人满意的答案。
要根据我上面列出的要求创建 Mock,执行以下操作应该就足够了:
def create_mock(spec: Any) -> Mock:
mock = Mock(spec_set=spec)
attributes_to_override = dir(spec)
for attr in filter(lambda name: not name.startswith("__"), attributes_to_override):
setattr(mock, attr, Mock(side_effect=AttributeError(f"{attr} not implemented")))
return mock