我有一个带有复杂 __init__
函数的类 MyClass
。
这个类有一个方法my_method(self)
,我想测试它。
my_method
仅需要类实例中的属性 my_attribute
。
有没有一种方法可以模拟类实例而不调用 __init__
并通过设置每个类实例的属性来代替?
我有:
# my_class.py
from utils import do_something
class MyClass(object):
def __init__(self, *args, **kwargs):
# complicated function which I would like to bypass when initiating a mocked instance class
pass
def my_method(self):
return do_something(self.my_attribute)
我尝试了什么
@mock.patch("my_class.MyClass")
def test_my_method(class_mock, attribute):
instance = class_mock.return_value
instance.my_attribute = attribute
example_instance = my_class.MyClass()
out_my_method = example_instance.my_method()
# then perform some assertions on `out_my_method`
但是,这仍然使用 __init__
我希望我们可以绕过或模拟。
最佳答案
正如我在评论中提到的,无需创建实例即可测试单个方法的一种方法是:
MyClass.my_method(any_object_with_my_attribute)
这个问题,就像 quamrana's answer 中的两个选项一样,是我们现在已经扩大了任何 future 变化的范围仅仅因为测试。如果对 my_method
的更改需要访问附加属性,我们现在必须更改实现和其他内容(SuperClass
、MockMyClass
,或者在本例中为any_object_with_my_attribute_and_another_one
)。
让我们举一个更具体的例子:
import json
class MyClass:
def __init__(self, filename):
with open(filename) as f:
data = json.load(f)
self.foo = data.foo
self.bar = data.bar
self.baz = data.baz
def my_method(self):
return self.foo ** 2
此处任何需要 MyClass
实例的测试。由于 __init__
中的文件访问而很痛苦。更具可测试性的实现会将数据访问方式和有效实例初始化的细节分开:
class MyClass:
def __init__(self, foo, bar, baz):
self.foo = foo
self.bar = bar
self.baz = baz
def my_method(self):
return self.foo ** 2
@classmethod
def from_json(cls, filename):
with open(filename) as f:
data = json.load(f)
return cls(data.foo, data.bar, data.baz)
您必须将 MyClass("path/to/file")
重构为 MyClass.from_json("path/to/file")
,但无论您已经 < em>拥有您可以使用的数据(例如在您的测试中) MyClass(1, 2, 3)
创建实例,不需要文件(您只需要在 from_json
本身的测试中考虑该文件)。这使得实例实际需要更加清晰,并且允许引入其他方式来构造实例而不改变接口(interface)。
关于python - 模拟类实例而不调用 `__init__`并模拟它们各自的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62549961/