模拟被测函数中使用的相同 class 的多个实例
Mocking multiple instances of the same class used in the function-under-test
我有一个使用相同 class 的 2 个实例的函数,我想使用 python 模拟测试该函数。
但我正在打破我的头我怎么能嘲笑这个。
我已经使用我的朋友 Google 和 Whosebug 找到了解决方案,但直到现在还没有找到。
作为简单的模拟示例,展示了我要测试的原理:
class MyClass(object): # this class is inside a module I'm not allowed to change.
def __init__(self, name, value):
self._name = name
self._value = value
def get_value(self):
return self._value
然后是被测模块(又是一个模拟实现来展示这个想法):
import my_class_module
def my_function():
a = my_class_module.MyClass('a', 3)
b = my_class_module.MyClass('b', 4)
return a.get_value() + b.get_value()
我想到的 my_function 单元测试的全局想法如下(当然这个想法目前还行不通):
mock.patch('module.my_class_module.MyClass')
def test_my_function(self, mock_my_class):
def _my_get_value(self): # ideally I would like to use get_value.return_value per instance, but I don't know how.
if self._name == 'a':
return 4 # Different values to make sure that we can verify that the mock is called
else:
return 5
# Next line is the one I'm wondering about since mock_myh_class.return_value should differ for each instance.
# But again this next line is already a work-around idea, since I don't know how to set the return-value of get_value for each instance.
mock_my_class.return_value.get_value.side_effect = my_get_value
exp_result = 9
result = module.my_function()
self.assertEqual(result, exp_result)
我缺少什么来完成这项工作?又名:我如何模拟相同 class 的 2 个实例?
您可以使用 mock.side_effect 创建 MyClass
的不同模拟实例。
例如
myclass.py
:
class MyClass(object):
def __init__(self, name, value):
self._name = name
self._value = value
def get_value(self):
return self._value
myfunction.py
:
import myclass
def my_function():
a = myclass.MyClass('a', 3)
b = myclass.MyClass('b', 4)
print('a:\n', a)
print('b:\n', b)
print('a and b are different instances of MyClass:', a != b)
return a.get_value() + b.get_value()
test_myfunction.py
:
import unittest
from unittest import mock
import myfunction
class TestMyFunctionModule(unittest.TestCase):
@mock.patch('myclass.MyClass')
def test_my_function(self, mock_my_class):
myclassInstanceMocks = [mock.Mock(name='a'), mock.Mock(name='b')]
myclassInstanceMocks[0].get_value.return_value = 4
myclassInstanceMocks[1].get_value.return_value = 5
mock_my_class.side_effect = myclassInstanceMocks
exp_result = 9
result = myfunction.my_function()
self.assertEqual(result, exp_result)
if __name__ == '__main__':
unittest.main()
带有覆盖率报告的单元测试结果:
a:
<Mock name='a' id='4572131536'>
b:
<Mock name='b' id='4572149072'>
a and b are different instances of MyClass: True
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Name Stmts Miss Cover Missing
-----------------------------------------------------------------------------
src/Whosebug/64170793/myclass.py 6 3 50% 3-4, 7
src/Whosebug/64170793/myfunction.py 8 0 100%
src/Whosebug/64170793/test_myfunction.py 14 0 100%
-----------------------------------------------------------------------------
TOTAL 28 3 89%
我有一个使用相同 class 的 2 个实例的函数,我想使用 python 模拟测试该函数。 但我正在打破我的头我怎么能嘲笑这个。 我已经使用我的朋友 Google 和 Whosebug 找到了解决方案,但直到现在还没有找到。
作为简单的模拟示例,展示了我要测试的原理:
class MyClass(object): # this class is inside a module I'm not allowed to change.
def __init__(self, name, value):
self._name = name
self._value = value
def get_value(self):
return self._value
然后是被测模块(又是一个模拟实现来展示这个想法):
import my_class_module
def my_function():
a = my_class_module.MyClass('a', 3)
b = my_class_module.MyClass('b', 4)
return a.get_value() + b.get_value()
我想到的 my_function 单元测试的全局想法如下(当然这个想法目前还行不通):
mock.patch('module.my_class_module.MyClass')
def test_my_function(self, mock_my_class):
def _my_get_value(self): # ideally I would like to use get_value.return_value per instance, but I don't know how.
if self._name == 'a':
return 4 # Different values to make sure that we can verify that the mock is called
else:
return 5
# Next line is the one I'm wondering about since mock_myh_class.return_value should differ for each instance.
# But again this next line is already a work-around idea, since I don't know how to set the return-value of get_value for each instance.
mock_my_class.return_value.get_value.side_effect = my_get_value
exp_result = 9
result = module.my_function()
self.assertEqual(result, exp_result)
我缺少什么来完成这项工作?又名:我如何模拟相同 class 的 2 个实例?
您可以使用 mock.side_effect 创建 MyClass
的不同模拟实例。
例如
myclass.py
:
class MyClass(object):
def __init__(self, name, value):
self._name = name
self._value = value
def get_value(self):
return self._value
myfunction.py
:
import myclass
def my_function():
a = myclass.MyClass('a', 3)
b = myclass.MyClass('b', 4)
print('a:\n', a)
print('b:\n', b)
print('a and b are different instances of MyClass:', a != b)
return a.get_value() + b.get_value()
test_myfunction.py
:
import unittest
from unittest import mock
import myfunction
class TestMyFunctionModule(unittest.TestCase):
@mock.patch('myclass.MyClass')
def test_my_function(self, mock_my_class):
myclassInstanceMocks = [mock.Mock(name='a'), mock.Mock(name='b')]
myclassInstanceMocks[0].get_value.return_value = 4
myclassInstanceMocks[1].get_value.return_value = 5
mock_my_class.side_effect = myclassInstanceMocks
exp_result = 9
result = myfunction.my_function()
self.assertEqual(result, exp_result)
if __name__ == '__main__':
unittest.main()
带有覆盖率报告的单元测试结果:
a:
<Mock name='a' id='4572131536'>
b:
<Mock name='b' id='4572149072'>
a and b are different instances of MyClass: True
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Name Stmts Miss Cover Missing
-----------------------------------------------------------------------------
src/Whosebug/64170793/myclass.py 6 3 50% 3-4, 7
src/Whosebug/64170793/myfunction.py 8 0 100%
src/Whosebug/64170793/test_myfunction.py 14 0 100%
-----------------------------------------------------------------------------
TOTAL 28 3 89%