python - 模拟类实例而不调用 `__init__`并模拟它们各自的属性

标签 python unit-testing mocking pytest

我有一个带有复杂 __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 的更改需要访问附加属性,我们现在必须更改实现其他内容(SuperClassMockMyClass,或者在本例中为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/

相关文章:

python - 使用 PyTorch 进行就地操作

python - 如何排除 ModelMultipleChoiceField 中的值?

android - android.test.AndroidTestCase 中的方法 setUp 未被模拟

php - 我在哪里可以找到 Simpletest 的扩展 HTML 报告程序?

ruby-on-rails - Rails Controller 测试 : Testing in isolation or integration?

python - Airflow : pass parameter from python function to MySQL Operator

python - 如何在 Python 包中包含共享 C 库

javascript - 具有外部依赖性的单元测试 ES6 类

c# - 比较两个 List<MyClass> : How to find out difference?

python - 条件模拟 : Call original function if condition does match