类方法中使用的Mock open()函数

2024-05-10 07:41:22 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图模仿在我的类的方法中使用的开放函数。 我找到了这个线程How do I mock an open used in a with statement (using the Mock framework in Python)?,但无法解决我的问题。unittest文档还显示了一个解决方案,它也没有模拟我的open https://docs.python.org/3/library/unittest.mock-examples.html#patch-decorators

这是使用open函数的方法的类:

#__init.py__

import json

class MyClass:

    def save_data_to_file(self, data):
        with open('/tmp/data.json', 'w') as file:
            json.dump(data, file)
...
mc = MyClass()

现在我找到了一个不同的解决方案。这是我的测试:

#save_to_file_test.py

from mymodule import MyClass
from mock import mock_open, patch
import ast

class SaveToFileTest(unittest.TestCase):

    def setUp(self):
        self.mc = MyClass()
        self.data = [
            {'id': 5414470, 'name': 'peter'},
            {'id': 5414472, 'name': 'tom'},
            {'id': 5414232, 'name': 'pit'},
        ]

    def test_save_data_to_file(self):
        m = mock_open()
        with patch('mymodule.open', m, create=True):
            self.mc.save_data_to_file(self.data)
            string = ''
            for call in m.return_value.write.mock_calls:
                string += (call[1][0])
            list = ast.literal_eval(string)
            assertEquals = (list, self.data)

我不确定这是否是测试应该写入文件的内容的最佳方法。 当我测试mock_调用时(call_args_list相同),这是传递给文件句柄的参数。 欢迎提出任何建议、改进和建议。


Tags: to方法inimportselfjsondatasave
1条回答
网友
1楼 · 发布于 2024-05-10 07:41:22

TL;博士

问题的核心是,为了能够正确地测试将要写入文件的数据,您应该同时模拟json.dump。实际上,在对测试方法进行一些重要的调整之前,我很难运行您的代码。

  • builtins.open而不是mymmodule.open模拟
  • 您在一个上下文管理器中,所以您应该检查m.return_value.__enter__.write,但是您实际上是从json.dump调用write,这是将调用write的地方。(下面详细介绍建议的解决方案)
  • 您还应该模拟json.dump以简单地验证它是用您的数据调用的

简而言之,针对上述问题,该方法可以重新编写为:

下面所有这些的详细信息

def test_save_data_to_file(self):
    with patch('builtins.open', new_callable=mock_open()) as m:
        with patch('json.dump') as m_json:
            self.mc.save_data_to_file(self.data)

            # simple assertion that your open was called 
            m.assert_called_with('/tmp/data.json', 'w')

            # assert that you called m_json with your data
            m_json.assert_called_with(self.data, m.return_value)

详细说明

为了关注我在您的代码中看到的问题,我强烈建议您做的第一件事,因为open是一个内置的,是模仿内置的,而且,您可以通过使用new_callableas为自己保存一行代码,因此您可以简单地执行以下操作:

with patch('builtins.open', new_callable=mock_open()) as m:

下一个问题,我看到你的代码,因为我运行这个问题,直到我真正作出以下调整时,你开始循环你的调用:

m.return_value.__enter__.return_value.write.mock_calls

要剖析这一点,您必须记住的是,您的方法使用的是上下文管理器。在使用上下文管理器时,编写工作实际上将在__enter__方法中完成。因此,从return_valuem中,您希望获得__enter__的返回值。

然而,这就把我们带到了问题的核心,你想测试什么。由于json.dump在写入文件时是如何工作的,因此在检查代码后进行写入的mock_calls实际上如下所示:

<MagicMock name='open().write' id='4348414496'>
call('[')
call('{')
call('"name"')
call(': ')
call('"peter"')
call(', ')
call('"id"')
call(': ')
call('5414470')
call('}')
call(', ')
call('{')
call('"name"')
call(': ')
call('"tom"')
call(', ')
call('"id"')
call(': ')
call('5414472')
call('}')
call(', ')
call('{')
call('"name"')
call(': ')
call('"pit"')
call(', ')
call('"id"')
call(': ')
call('5414232')
call('}')
call(']')
call.__str__()

这可不好玩。所以,这就引出了下一个可以尝试的解决方案:Mockjson.dump

你不应该测试json.dump,你应该测试用正确的参数调用它。话虽如此,你也可以用类似的方式模仿你的嘲笑,然后做这样的事情:

with patch('json.dump') as m_json:

现在,有了它,您可以大大简化您的测试代码,简单地验证用您正在测试的数据调用该方法。所以,有了这个,当你把它放在一起的时候,你会得到这样的东西:

def test_save_data_to_file(self):
    with patch('builtins.open', new_callable=mock_open()) as m:
        with patch('json.dump') as m_json:
            self.mc.save_data_to_file(self.data)

            # simple assertion that your open was called 
            m.assert_called_with('/tmp/data.json', 'w')

            # assert that you called m_json with your data
            m_json.assert_called_with(self.data, m.return_value.__enter__.return_value)

如果您对进一步的重构感兴趣,以使测试方法更干净一些,您还可以将修补设置为decorator,使代码在方法中更干净:

@patch('json.dump')
@patch('builtins.open', new_callable=mock_open())
def test_save_data_to_file(self, m, m_json):
    self.mc.save_data_to_file(self.data)

    # simple assertion that your open was called
    m.assert_called_with('/tmp/data.json', 'w')

    # assert that you called m_json with your data
    m_json.assert_called_with(self.data, m.return_value.__enter__.return_value)

在这里,检查是您最好的朋友,查看在哪些步骤调用了哪些方法,以进一步帮助测试。祝你好运。

相关问题 更多 >