修补在单元测试的依赖项中动态生成的数据类属性
Patch a dataclass attribute which is dynamically generated in its dependency in unit testing
我是单元测试的新手。我过去使用过模拟、修补,但我遇到的情况对我来说创建单元测试有点复杂。
所以我有一个文件:parent.py
包含以下数据 class
import multiprocessing
from dataclasses import dataclass
@dataclass
class ParentClass:
cpu_count: int = multiprocessing.cpu_count()
我有另一个模块 child.py
具有以下数据 class
from Whosebug.parent import ParentClass
from dataclasses import dataclass
@dataclass
class ChildClass(ParentClass):
some_attribute_1: int = 1
some_attribute_2: int = 2
....
最后,我有第三个模块 actual_function.py
使用这些数据 classes.
from stack_overflow.child import ChildClass
def get_cpu_count_and_attributes(cc: ChildClass):
return cc.cpu_count, cc.some_attribute_1
在这里,我想对print_cpu_count_and_attributes
函数进行单元测试。修补在这里如何工作?我创建了以下测试用例,但它失败了。我系统中的 cpu_count 是 16,但我想用 return 值 8 模拟它,以便它可以在具有不同内核数的其他机器上运行
from unittest import mock
from stack_overflow.actual_function import *
from stack_overflow.child import ChildClass
@mock.patch('stack_overflow.parent.multiprocessing.cpu_count', return_value=8)
def test_print_cpu_count_and_attributes():
cc = ChildClass()
assert get_cpu_count_and_attributes(cc) == (8, 1)
这是文件夹结构。
Whosebug
├── __init__.py
├── actual_function.py
├── child.py
├── parent.py
└── test_function.py
如果您正在尝试测试 ChildClass
,您应该为它设置路径,而不是不同模块中的父项。
启发式模拟:
- 修补你测试的内容
- 尽可能接近目标函数的补丁
你的补丁不起作用的原因是 python 不会 re-evaluate 模块和 class 补丁后的层次结构。由于 python 是动态的,所以发生的事情是
- 家长class评价
- 子class参考父class对象
评估
- 您在父模块中修补父 class,但在
actual_function
中测试代码,并且 ChildClass
引用了旧的原始 Parent
,因为 mock
实际上是在 parent.py
命名空间中更改 Parent
的对象属性。
另外,看看mock documentation on patching point
您的案例示例:
with mock.patch.object(ChildClass, 'cpu_count', new_callable=mock.PropertyMock) as m:
m.return_value = 42
get_cpu_count_and_attributes(ChildClass())
你不应该改变 inherited attributes/properties,你应该把补丁 放在目标的顶部 (因此得名 ;) )
我是单元测试的新手。我过去使用过模拟、修补,但我遇到的情况对我来说创建单元测试有点复杂。
所以我有一个文件:parent.py
包含以下数据 class
import multiprocessing
from dataclasses import dataclass
@dataclass
class ParentClass:
cpu_count: int = multiprocessing.cpu_count()
我有另一个模块 child.py
具有以下数据 class
from Whosebug.parent import ParentClass
from dataclasses import dataclass
@dataclass
class ChildClass(ParentClass):
some_attribute_1: int = 1
some_attribute_2: int = 2
....
最后,我有第三个模块 actual_function.py
使用这些数据 classes.
from stack_overflow.child import ChildClass
def get_cpu_count_and_attributes(cc: ChildClass):
return cc.cpu_count, cc.some_attribute_1
在这里,我想对print_cpu_count_and_attributes
函数进行单元测试。修补在这里如何工作?我创建了以下测试用例,但它失败了。我系统中的 cpu_count 是 16,但我想用 return 值 8 模拟它,以便它可以在具有不同内核数的其他机器上运行
from unittest import mock
from stack_overflow.actual_function import *
from stack_overflow.child import ChildClass
@mock.patch('stack_overflow.parent.multiprocessing.cpu_count', return_value=8)
def test_print_cpu_count_and_attributes():
cc = ChildClass()
assert get_cpu_count_and_attributes(cc) == (8, 1)
这是文件夹结构。
Whosebug
├── __init__.py
├── actual_function.py
├── child.py
├── parent.py
└── test_function.py
如果您正在尝试测试 ChildClass
,您应该为它设置路径,而不是不同模块中的父项。
启发式模拟:
- 修补你测试的内容
- 尽可能接近目标函数的补丁
你的补丁不起作用的原因是 python 不会 re-evaluate 模块和 class 补丁后的层次结构。由于 python 是动态的,所以发生的事情是
- 家长class评价
- 子class参考父class对象 评估
- 您在父模块中修补父 class,但在
actual_function
中测试代码,并且ChildClass
引用了旧的原始Parent
,因为mock
实际上是在parent.py
命名空间中更改Parent
的对象属性。
另外,看看mock documentation on patching point
您的案例示例:
with mock.patch.object(ChildClass, 'cpu_count', new_callable=mock.PropertyMock) as m:
m.return_value = 42
get_cpu_count_and_attributes(ChildClass())
你不应该改变 inherited attributes/properties,你应该把补丁 放在目标的顶部 (因此得名 ;) )