【问题标题】:Python mock returns invalid valuePython 模拟返回无效值
【发布时间】:2021-12-02 09:11:04
【问题描述】:

我有以下结构:

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 调用应该返回给定的 URL 列表,但它会返回一个转换为空列表的 Mock 对象。

Python 版本是 3.9。

怎么了?

【问题讨论】:

  • 你在模拟类而不是实例,你需要一个额外的return_value:mock_sitemap_parser.return_value. parse_sitemap.return_value = 1
  • @MrBeanBremen 谢谢,这行得通!您能否将其发布为答案,以便我接受?

标签: python python-3.x unit-testing python-unittest python-mock


【解决方案1】:

如果模拟一个成员函数,你必须模拟模拟实例对象上的函数,而不是模拟类对象上的函数。这可能并不完全直观,因为成员函数属于一个类,但您可能会将其视为绑定方法与未绑定方法 - 您必须模拟绑定方法。

使用Mock,通过在类对象上使用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',
        ]
        ...

(拆分模拟仅供参考)

【讨论】:

    猜你喜欢
    • 2015-09-09
    • 1970-01-01
    • 2016-03-29
    • 1970-01-01
    • 1970-01-01
    • 2020-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多