【问题标题】:Can a MagicMock object be iterated over?可以迭代 MagicMock 对象吗?
【发布时间】:2025-12-07 03:30:01
【问题描述】:

我想做的是这个……

x = MagicMock()
x.iter_values = [1, 2, 3]

for i in x:
    i.method()

我正在尝试为此函数编写单元测试,但我不确定如何在不调用某些外部资源的情况下模拟所有调用的方法...

def wiktionary_lookup(self):
    """Looks up the word in wiktionary with urllib2, only to be used for inputting data"""
    wiktionary_page = urllib2.urlopen(
        "http://%s.wiktionary.org/wiki/%s" % (self.language.wiktionary_prefix, self.name))
    wiktionary_page = fromstring(wiktionary_page.read())
    definitions = wiktionary_page.xpath("//h3/following-sibling::ol/li")
    print definitions.text_content()
    defs_list = []
    for i in definitions:
        print i
        i = i.text_content()
        i = i.split('\n')
        for j in i:
            # Takes out an annoying "[quotations]" in the end of the string, sometimes.
            j = re.sub(ur'\u2003\[quotations \u25bc\]', '', j)
            if len(j) > 0:
                defs_list.append(j)
    return defs_list

编辑:

我可能在滥用模拟,我不确定。我正在尝试在不调用外部服务的情况下对 wiktionary_lookup 方法进行单元测试...所以我模拟 urlopen ..我模拟 fromstring.xpath() 但据我所知,我还需要遍历 @ 的返回值987654324@ 并调用方法“text_contents()”,这就是我在这里要做的。

如果我完全误解了如何对这个方法进行单元测试,那么请告诉我哪里出错了......

编辑(添加当前单元测试代码)

@patch("lang_api.models.urllib2.urlopen")
@patch("lang_api.models.fromstring")
def test_wiktionary_lookup_2(self, fromstring, urlopen):
    """Looking up a real word in wiktionary, should return a list"""
    fromstring().xpath.return_value = MagicMock(
        content=["test", "test"], return_value='test\ntest2')
    # A real word should give an output of definitions
    output = self.things.model['word'].wiktionary_lookup()
    self.assertEqual(len(output), 2)

【问题讨论】:

  • 你想在你的单元测试中准确地模拟什么?另外,您的MagicMock 示例。你到底想用那个列表做什么?我怀疑你在这里滥用模拟。但我不确定你到底想做什么。
  • @idjaw,将响应添加为编辑
  • 您能否实际展示您的单元测试代码,看看可以提供哪些改进建议?
  • @idjaw 这是我目前所拥有的。我刚刚开始尝试遍历 MagicMock 中的值,所以它现在看起来非常不完整
  • 迟到总比不到好。我不知道您是否仍然坚持这一点,或者想出了如何做到这一点,但我想分享我的解决方案。如果您仍然卡住,希望这会有所帮助。干杯。

标签: python django unit-testing mocking


【解决方案1】:

您真正想要做的不是返回 Mockreturn_value=[]。您实际上想要返回 listMock 对象。以下是包含正确组件的测试代码的 sn-p 和一个小示例,用于展示如何测试循环中的一个迭代:

@patch('d.fromstring')
@patch('d.urlopen')
def test_wiktionary(self, urlopen_mock, fromstring_mock):
    urlopen_mock.return_value = Mock()
    urlopen_mock.return_value.read.return_value = "some_string_of_stuff"

    mocked_xpath_results = [Mock()]
    fromstring_mock.return_value.xpath.return_value = mocked_xpath_results

    mocked_xpath_results[0].text_content.return_value = "some string"

所以,剖析上面的代码来解释为纠正您的问题所做的工作:

帮助我们测试 for 循环中的代码的第一件事是创建一个模拟对象列表:

mocked_xpath_results = [Mock()]

那么,如你所见,

fromstring_mock.return_value.xpath.return_value = mocked_xpath_results

我们将xpath 调用的return_value 设置为每个mocked_xpath_results 的模拟列表。

作为如何在列表中执行操作的示例,我添加了如何在循环中模拟,如下所示:

mocked_xpath_results[0].text_content.return_value = "some string"

在单元测试中(这可能是一个见仁见智的问题)我喜欢明确,所以我明确地访问列表项并确定应该发生什么。

希望这会有所帮助。

【讨论】:

  • 感谢您的回答。我最终将来自真实维基词典的响应存储为一个变量,然后将其导入并运行一个半真实的fromstring,当我有时间时,我会用它来重构。谢谢
最近更新 更多