Python 模拟 returns 无效值
Python mock returns invalid value
我有以下结构:
sources/
- parser/
- sources_parser.py # SourcesParser class is here
- tests/
- test_sources_parsers.py # SourcesParserTest is here
sources_parser.py
:
from sources.parser.sitemap_parser import SitemapParser
class SourcesParser(object):
__sitemap_parser: SitemapParser
def __init__(self) -> None:
super().__init__()
self.__sitemap_parser = SitemapParser()
def parse(self):
# ...
urls = self.__parse(source)
self.logger.info(f'Got {len(urls)} URLs')
def __parse(self, source: NewsSource) -> List[str]:
results = self.__sitemap_parser.parse_sitemap(source.url)
self.logger.info(f'Results: {results}, is list: {isinstance(results, list)}')
return results
测试:
class SourcesParserTest(TestCase):
@patch('sources.parser.sources_parser.SitemapParser')
def test_normal_parse(self, mock_sitemap_parser):
mock_sitemap_parser.parse_sitemap.return_value = [
'https://localhost/news/1',
'https://localhost/news/2',
'https://localhost/news/3',
]
parser = SourcesParser()
parser.parse()
日志是:
Results: <MagicMock name='SitemapParser().parse_sitemap()' id='5105954240'>, is list: False
Got 0 URLs
如果我理解正确,parse_sitemap
调用应该 return 给定的 URL 列表,而是 return 一个 Mock
对象,该对象被转换为空列表。
Python 版本是 3.9.
怎么了?
如果模拟一个成员函数,你必须模拟模拟实例对象上的函数,而不是模拟 class 对象上的函数。这可能不完全直观,因为成员函数属于 class,但您可以将其视为绑定方法与未绑定方法 - 您必须模拟绑定方法。
使用 Mock
,通过在 class 对象上使用 return_value
来模拟实例,类似于模拟函数调用的结果,因此在您的情况下,您需要:
@patch('sources.parser.sources_parser.SitemapParser')
def test_normal_parse(self, mock_sitemap_parser):
mocked_parser = mock_sitemap_parser.return_value # mocked instance
mock_parser.parse_sitemap.return_value = [
'https://localhost/news/1',
'https://localhost/news/2',
'https://localhost/news/3',
]
...
(拆分模拟仅供参考)
我有以下结构:
sources/
- parser/
- sources_parser.py # SourcesParser class is here
- tests/
- test_sources_parsers.py # SourcesParserTest is here
sources_parser.py
:
from sources.parser.sitemap_parser import SitemapParser
class SourcesParser(object):
__sitemap_parser: SitemapParser
def __init__(self) -> None:
super().__init__()
self.__sitemap_parser = SitemapParser()
def parse(self):
# ...
urls = self.__parse(source)
self.logger.info(f'Got {len(urls)} URLs')
def __parse(self, source: NewsSource) -> List[str]:
results = self.__sitemap_parser.parse_sitemap(source.url)
self.logger.info(f'Results: {results}, is list: {isinstance(results, list)}')
return results
测试:
class SourcesParserTest(TestCase):
@patch('sources.parser.sources_parser.SitemapParser')
def test_normal_parse(self, mock_sitemap_parser):
mock_sitemap_parser.parse_sitemap.return_value = [
'https://localhost/news/1',
'https://localhost/news/2',
'https://localhost/news/3',
]
parser = SourcesParser()
parser.parse()
日志是:
Results: <MagicMock name='SitemapParser().parse_sitemap()' id='5105954240'>, is list: False
Got 0 URLs
如果我理解正确,parse_sitemap
调用应该 return 给定的 URL 列表,而是 return 一个 Mock
对象,该对象被转换为空列表。
Python 版本是 3.9.
怎么了?
如果模拟一个成员函数,你必须模拟模拟实例对象上的函数,而不是模拟 class 对象上的函数。这可能不完全直观,因为成员函数属于 class,但您可以将其视为绑定方法与未绑定方法 - 您必须模拟绑定方法。
使用 Mock
,通过在 class 对象上使用 return_value
来模拟实例,类似于模拟函数调用的结果,因此在您的情况下,您需要:
@patch('sources.parser.sources_parser.SitemapParser')
def test_normal_parse(self, mock_sitemap_parser):
mocked_parser = mock_sitemap_parser.return_value # mocked instance
mock_parser.parse_sitemap.return_value = [
'https://localhost/news/1',
'https://localhost/news/2',
'https://localhost/news/3',
]
...
(拆分模拟仅供参考)