在Python中模拟数据类时如何使用spec

问题描述 投票:0回答:4

我正在尝试使用 backport 包将我们的命名元组类移植到 Python 3.6 中的数据类中。但是,我注意到在模拟数据类时,您不能再使用“spec”关键字。我认为这是因为数据类代码是自动生成的。

from dataclasses import dataclass
import mock

@dataclass
class A:
    aaa: str
    bbb: int


m = mock.Mock(spec=A)

m.aaa

这是我得到的错误:

AttributeError: Mock object has no attribute 'aaa'

知道是否有任何方法可以自动将原始对象的所有属性设置为模拟对象?我有很多包含大量数据的数据类。如果我尝试手动一一设置这些值,那将是非常乏味的。

python attributes mocking python-dataclasses
4个回答
10
投票

我最终使用这个通用辅助函数来实现规范对常规类的作用:

import mock
from dataclasses import fields


def create_dataclass_mock(obj):
    return mock.Mock(spec=[field.name for field in fields(obj)])

6
投票

您还可以将具有虚拟值的实例传递给

spec

from unittest.mock import Mock
from dataclasses import dataclass

@dataclass
class A:
    aaa: str
    bbb: int

m = Mock(spec=A(None, None))

print(m.bbb)
# <Mock name='mock.bbb' id='139766470904856'>

1
投票

基于mohi666的回答。如果您还想防止设置数据类中未指定的 Mock 属性,请使用

spec_set
而不是
spec

import mock
from dataclasses import dataclass, fields

@dataclass
class A:
   x: str


def create_dataclass_mock(obj):
    return mock.Mock(spec_set=[field.name for field in fields(obj)])

m = create_dataclass_mock(A)
m.x = 'test' # works
m.y = 'another test' # raises AttributeError

0
投票

数据类字段实际上是作为实例变量实现的。您有 4 个选择:

  • 为该字段指定默认值:
@dataclass()
class MyDataClass1:
    my_field: str = field(default="my_field_val")
m = Mock(spec=MyDataClass1("my_field_val"))
print(m.my_field)
  • 在数据类的构造函数调用中将字段的值作为参数提供:
@dataclass()
class MyDataClass2:
    my_field: str = field()
m = Mock(spec=MyDataClass2("my_field_val"))
print(m.my_field)
  • 实例化模拟:
@dataclass()
class MyDataClass3:
    my_field: str = field()
m = Mock(spec=MyDataClass3)
m_inst = m()
print(m_inst.my_field)
  • 使用列表理解来实例化规范中的所有字段:
@dataclass()
class MyDataClass4:
    my_field: str = field()
m = Mock(spec_set=[field.name for field in fields(MyDataClass4)])
print(m.my_field)
© www.soinside.com 2019 - 2024. All rights reserved.