【问题标题】:How to mock an instance attribute initilized by a function如何模拟由函数初始化的实例属性
【发布时间】:2020-03-27 15:35:28
【问题描述】:

我正在为一个在不是构造函数的函数中设置实例属性的类编写一些单元测试。这个类是这样的

class MyClass:
    def __init__(self):
        self.__A = False
        self.__B = False

    def set_C(self):
        self.__C = True

    def my_func(self):
        self.set_C()

        if self.__A:
            self.print_val(self.__A)
        if self.__B:
            self.print_val(self.__B)
        if self.__C:
            self.print_val(self.__C)

    def print_val(self, val):
        print(val)

我正在尝试为my_func() 编写一个测试,以检查print_val() 是否在属性评估为真时运行。 我到目前为止的测试是这个(忽略导入)

class TestMyClass:

    @patch("MyClass.print_val")
    def test_my_func(self, mock_print_val):
        my_class = MyClass()
        # setattr(my_class, "C", False)
        with patch.object(my_class, "C", True) as mock_C:
            my_class.my_func()
            mock_print_val.assert_called()

稍后我将编辑 assert 调用以检查它是否使用特定参数调用,但基本思想是检查 print_val() 是否运行。

我注意到没有setattr(my_class, "C", False) 会给我以下错误AttributeError: <...> does not have attribute 'C'

使用setattr() 进行调试时,我可以在打印之前在变量窗口中的Protected Attributes 下看到“C”属性,但它仍然给出错误 (实际上我不确定setattr() 是否是正确的方法,只是我正在尝试一些东西,因为它说属性不存在)

我也知道,如果我将代码更改为以下以修补 __init__ 的属性,它就可以正常工作

class TestMyClass:

    @patch("MyClass.print_val")
    def test_my_func(self, mock_print_val):
        my_class = MyClass()
        with patch.object(my_class, "A", True) as mock_C:
            my_class.my_func()
            mock_print_val.assert_called()

从我所做的研究中,我看到了类似的问题,但它们是针对类属性的,或者略有不同。如果之前有人问过这个问题,我很抱歉,我错过了。

编辑: 在试图找出解决方案时,我注意到我可以简单地做

class TestMyClass:

    @patch("MyClass.print_val")
    def test_my_func(self, mock_print_val):
        my_class = MyClass()
        my_class.C = True
        my_class.my_func()
        mock_print_val.assert_called()

如果属性C 是公开的并且将其打印为print_val(self.C) 将不会导致任何问题。我编辑了原始问题以澄清该属性应该受到保护而不是公开。

【问题讨论】:

    标签: python mocking patch


    【解决方案1】:

    在进行其他测试时,我设法找到了解决方案..

    我拥有的是:

    class TestMyClass:
    
        @patch("MyClass.print_val")
        def test_my_func(self, mock_print_val):
            my_class = MyClass()
            my_class._MyClass__C = True
            my_class.my_func()
            mock_print_val.assert_called()
    

    这似乎奏效了。如果MyClass 中的属性以单个下划线为前缀或根本不以my_class._Cmy_class._c 为前缀,则可以使用,但由于它以两个下划线为前缀,我必须使用my_class._MyClass__C

    我不知道这是否是一个安全且推荐的解决方案..

    【讨论】:

    • 对于测试,我会说没问题。应用于__-prefixed 名称的名称修饰是为了更难在子类中意外隐藏名称。鉴于您正在使用名称修饰,这是从方法外部访问属性的方法。
    猜你喜欢
    • 2016-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-27
    • 1970-01-01
    相关资源
    最近更新 更多