Python - 如何正确模拟 class 方法中的 cls 参数以引用静态变量
Python - How to properly mock the cls argument in a class method to reference static variable
背景
Python 及其单元测试模块相对较新。在测试中模拟静态 class 变量时遇到问题。
(仅当原始 class 方法通过其第一个参数引用其自己的 class 变量时:cls)
示例:
正在测试的 class 和 class 方法的简化版本:
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()
问题:
为什么 mock 只修补 A 引用而不修补 cls 引用?
解决的方向应该是什么,才能成功修补cls参数,所以class方法可以通过上面的测试
您已经在测试模块中导入了 A
,因此您已经引用了原始未修补的 A
,这就是您所说的 my_method
。
- Why does mock only patches the A reference and not the cls reference?
因为那是你修补的。补丁通过拦截 名称查找 来工作,它不会(也不能)按字面意思替换就地对象。当您想要修补具有多个名称(A
和 cls
,在这种情况下)的对象时,您必须修补每个名称查找。
- In what direction should the solution be, in order to successfully patch the cls argument as well, so class method can pass the test shown above.
直接把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
背景
Python 及其单元测试模块相对较新。在测试中模拟静态 class 变量时遇到问题。
(仅当原始 class 方法通过其第一个参数引用其自己的 class 变量时:cls)
示例:
正在测试的 class 和 class 方法的简化版本:
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()
问题:
为什么 mock 只修补 A 引用而不修补 cls 引用?
解决的方向应该是什么,才能成功修补cls参数,所以class方法可以通过上面的测试
您已经在测试模块中导入了 A
,因此您已经引用了原始未修补的 A
,这就是您所说的 my_method
。
- Why does mock only patches the A reference and not the cls reference?
因为那是你修补的。补丁通过拦截 名称查找 来工作,它不会(也不能)按字面意思替换就地对象。当您想要修补具有多个名称(A
和 cls
,在这种情况下)的对象时,您必须修补每个名称查找。
- In what direction should the solution be, in order to successfully patch the cls argument as well, so class method can pass the test shown above.
直接把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