Python-如何在类方法中正确模拟cls参数以引用静态变量

时间:2018-07-14 22:02:44

标签: python mocking python-unittest class-method static-variables

背景

Python及其unittest模块相对较新。在测试中模拟静态类变量时遇到麻烦。

(仅当原始类方法通过其第一个参数cls引用其自己的类变量时)

示例:

正在测试的类和类方法的简化版本:

a.py
class A:
  # class variable
  my_list = []

  @classmethod
  def my_method(cls, item):
    print cls  # []  unable to mock this, why?
    print A    # [1,2,3] mocked as intended
    cls.my_list.append(item)

测试:

import unittest
from mock import patch
from a import A

class Test(unittest.testCase):
  def test_my_method(self):
    with patch("a.A") as mock_A:

      # mocking the class variable
      mock_A.my_list = [1,2,3]

      # test call class method
      A.my_method(4)

      # assert the appended list to expected output
      self.assertEqual(mock_A.my_list, [1,2,3,4])
      # should evaluate to true, but  fails the test

if __name__ == "__main__":
  unittest.main()

问题

  1. 为什么只模拟A引用而不修补cls引用?

  2. 解决方案应该朝哪个方向发展,以便也成功修补cls参数,因此类方法可以通过上面显示的测试。

1 个答案:

答案 0 :(得分:1)

您已经在测试模块中导入了A,因此您已经有了对原始未修补A的引用,这就是您所说的my_method

  
      
  1. 为什么只模拟A引用而不是cls引用?
  2.   

因为这就是您修补的内容。修补程序通过拦截名称查找起作用,它不能(也不能)从字面上替换对象。如果要修补具有多个名称(在这种情况下为Acls的对象),则必须修补每个名称查找。

  
      
  1. 解决方案应该朝哪个方向发展,以便也成功修补cls参数,因此类方法可以通过上面显示的测试。
  2.   

最好直接修补class属性:

class Test(unittest.TestCase):

  def test_my_method(self):
      with patch("a.A.my_list", [1,2,3]):
          A.my_method(4)
          self.assertEqual(A.my_list, [1,2,3,4])
      self.assertEqual(A.my_list, [])  # note: the mock is undone here