Python 中的单元测试:嵌套模拟对象
Unit testing in Python: Nesting mocked objects
我是 Python 中的单元测试新手。我正在尝试对执行以下操作的方法进行单元测试:
MyClass:
client : Client
def __init__(client):
self.client=client
def method_to_test(self):
images = self.client.get_stuff()
image = images[0]
result = []
for region in image.regions:
result.append(region.region_id)
return result
我已经尝试模拟和嵌套所有涉及的 类:Client、Image 和 ImageRegion。但在某些时候,模拟崩溃了,我的测试失败了。有没有一种方法可以模拟事物,以便可以做类似的事情:
def test_method_to_test():
result = MyClass(mock_client).method_to_test()
assert dummy_region_id in result
...或者在这种情况下使用嵌套自定义对象进行测试的更好方法?
我最近的尝试是这样的:
with patch('package.module.ImageRegion') as MockRegion:
region = MockRegion()
region.region_id.return_value = dummy_region_id
with patch('package.module.Image') as MockImage:
image = MockImage()
image.regions.return_value = [region]
with patch('package.module.Client') as MockClient:
mock_client = MockClient()
mock_client.get_regions.return_value = [image]
result = MyClass(mock_client).method_to_test()
assert dummy_region_id in result
您可以使用 unittest.mock 创建模拟对象并使用依赖注入将模拟对象传递给 MyClass
。
例如
myclass.py
:
class MyClass:
def __init__(self, client):
self.client = client
def method_to_test(self):
images = self.client.get_stuff()
image = images[0]
result = []
for region in image.regions:
result.append(region.region_id)
return result
test_myclass.py
:
import unittest
from unittest.mock import Mock
from collections import namedtuple
from myclass_63948475 import MyClass
Image = namedtuple('Image', ['regions'])
Region = namedtuple('Region', 'region_id')
class TestMyClass(unittest.TestCase):
def test_method_to_test(self):
regions = [Region('1'), Region('2'), Region('3')]
images = [Image(regions=regions)]
mock_client = Mock()
mock_client.get_stuff.return_value = images
myclass = MyClass(mock_client)
actual = myclass.method_to_test()
mock_client.get_stuff.assert_called_once()
self.assertEqual(actual, ['1', '2', '3'])
if __name__ == '__main__':
unittest.main()
带有覆盖率报告的单元测试结果:
coverage run /Users/ldu020/workspace/github.com/mrdulin/python-codelab/src/Whosebug/63948475/test_myclass_63948475.py && coverage report -m
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Name Stmts Miss Cover Missing
-----------------------------------------------------------------------------------
src/Whosebug/63948475/myclass_63948475.py 10 0 100%
src/Whosebug/63948475/test_myclass_63948475.py 18 0 100%
-----------------------------------------------------------------------------------
TOTAL 28 0 100%
我是 Python 中的单元测试新手。我正在尝试对执行以下操作的方法进行单元测试:
MyClass:
client : Client
def __init__(client):
self.client=client
def method_to_test(self):
images = self.client.get_stuff()
image = images[0]
result = []
for region in image.regions:
result.append(region.region_id)
return result
我已经尝试模拟和嵌套所有涉及的 类:Client、Image 和 ImageRegion。但在某些时候,模拟崩溃了,我的测试失败了。有没有一种方法可以模拟事物,以便可以做类似的事情:
def test_method_to_test():
result = MyClass(mock_client).method_to_test()
assert dummy_region_id in result
...或者在这种情况下使用嵌套自定义对象进行测试的更好方法?
我最近的尝试是这样的:
with patch('package.module.ImageRegion') as MockRegion:
region = MockRegion()
region.region_id.return_value = dummy_region_id
with patch('package.module.Image') as MockImage:
image = MockImage()
image.regions.return_value = [region]
with patch('package.module.Client') as MockClient:
mock_client = MockClient()
mock_client.get_regions.return_value = [image]
result = MyClass(mock_client).method_to_test()
assert dummy_region_id in result
您可以使用 unittest.mock 创建模拟对象并使用依赖注入将模拟对象传递给 MyClass
。
例如
myclass.py
:
class MyClass:
def __init__(self, client):
self.client = client
def method_to_test(self):
images = self.client.get_stuff()
image = images[0]
result = []
for region in image.regions:
result.append(region.region_id)
return result
test_myclass.py
:
import unittest
from unittest.mock import Mock
from collections import namedtuple
from myclass_63948475 import MyClass
Image = namedtuple('Image', ['regions'])
Region = namedtuple('Region', 'region_id')
class TestMyClass(unittest.TestCase):
def test_method_to_test(self):
regions = [Region('1'), Region('2'), Region('3')]
images = [Image(regions=regions)]
mock_client = Mock()
mock_client.get_stuff.return_value = images
myclass = MyClass(mock_client)
actual = myclass.method_to_test()
mock_client.get_stuff.assert_called_once()
self.assertEqual(actual, ['1', '2', '3'])
if __name__ == '__main__':
unittest.main()
带有覆盖率报告的单元测试结果:
coverage run /Users/ldu020/workspace/github.com/mrdulin/python-codelab/src/Whosebug/63948475/test_myclass_63948475.py && coverage report -m
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Name Stmts Miss Cover Missing
-----------------------------------------------------------------------------------
src/Whosebug/63948475/myclass_63948475.py 10 0 100%
src/Whosebug/63948475/test_myclass_63948475.py 18 0 100%
-----------------------------------------------------------------------------------
TOTAL 28 0 100%