Python Mock - 模拟几个打开的

发布于 2025-01-07 13:40:20 字数 756 浏览 1 评论 0原文

读完这篇文章后:如何模拟 with 语句中使用的 open (使用 Python 中的 Mock 框架)?

我'我能够使用以下命令模拟 python 中的 open 函数:

with patch(open_name, create=True) as mock_open:
    mock_open.return_value = MagicMock(spec=file)
    m_file = mock_open.return_value.__enter__.return_value
    m_file.read.return_value = 'text1'

    diffman = Diffman()
    diffman.diff(path1, path2)

当我的测试方法使用一个 open 语句时,它效果很好。这是我测试的方法:

def diff(self, a, b):
    with open(a, 'r') as old:
        with open(b, 'r') as new:
            oldtext = old.read()
            newtext = new.read()

oldtext 和 newtext 的值相同(此处为“text1”)。

我希望旧文本为“text1”,新文本为“text2”。

我该怎么做?

After reading this : How do I mock an open used in a with statement (using the Mock framework in Python)?

I'm able to mock the open function in python using :

with patch(open_name, create=True) as mock_open:
    mock_open.return_value = MagicMock(spec=file)
    m_file = mock_open.return_value.__enter__.return_value
    m_file.read.return_value = 'text1'

    diffman = Diffman()
    diffman.diff(path1, path2)

It works well when my tested method used one open statement. Here is my tested method :

def diff(self, a, b):
    with open(a, 'r') as old:
        with open(b, 'r') as new:
            oldtext = old.read()
            newtext = new.read()

The values of oldtext and newtext are the same ('text1' here).

I would like to have 'text1' for the oldtext and 'text2' for the newtext.

How can I do this ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

誰ツ都不明白 2025-01-14 13:40:20

这是获得您想要的东西的快速方法。它有点作弊,因为被测试方法中的两个文件对象是同一个对象,我们只是在每次读取后更改读取调用的返回值。如果您希望文件对象不同,您可以在多个层中使用相同的技术,但这会非常混乱,并且可能不必要地掩盖测试的意图。

将此行: 替换

    m_file.read.return_value = 'text1'

为:

    reads = ['text1', 'text2']
    m_file.read.side_effect = lambda: reads.pop(0)

Here's a quick way of getting what you want. It cheats a little bit because the two file objects in the method under test are the same object and we're just changing the return value of the read call after each read. You can use the same technique in multiple layers if you want the file objects to be different, but it will be quite messy and it may disguise the intent of the test unnecessarily.

Replace this line:

    m_file.read.return_value = 'text1'

with:

    reads = ['text1', 'text2']
    m_file.read.side_effect = lambda: reads.pop(0)
黑白记忆 2025-01-14 13:40:20

也许一个好的解决方案就是以一种更适合轻松测试的方式编写代码。在“diff”的情况下,让 diff 将已打开的文件对象作为参数似乎很容易(无可否认,没有太多其他上下文)。这可能是在代码中进行的一个相当小的更改,并且使测试变得非常容易,因为当您测试它时,您可以轻松地向 diff() 提供模拟文件对象,而不是尝试跳过模拟同一文件的两个实例内置函数作为上下文管理器在...本身...或其他东西内调用;-)

import StringIO

diff(a, b):
  oldtext = a.read()
  newtext = b.read()

def test_diff():
  a = StringIO.StringIO('text1')
  b = StringIO.StringIO('text2')

  res = diff(a, b)
  <some assertion here>

这适合您的情况吗?

Perhaps a good possible solution is just to write the code in a way that better lends itself to easily testing it. In the case of 'diff', it seems easy enough (not having much other context, admittedly) to have diff take as arguments already-opened file objects. This is likely a fairly small change to make in the code, and makes testing very easy, since you can then easily provide mock file objects to diff() when you test it, instead of trying to jump through hoops mocking two instances of the same builtin function as a context manager called within... itself... or something ;-)

import StringIO

diff(a, b):
  oldtext = a.read()
  newtext = b.read()

def test_diff():
  a = StringIO.StringIO('text1')
  b = StringIO.StringIO('text2')

  res = diff(a, b)
  <some assertion here>

Would that work for your case?

放赐 2025-01-14 13:40:20

刚刚找到另一个解决方案:

open_mock1 = mock.mock_open(read_data="file1 data")
open_mock2 = mock.mock_open(read_data="file2 data")

def open_mock_side(file_name, *args, **kwargs):
    # can be refactored to use a dict
    if file_name.endswith("folder/file1.txt"):
        return open_mock1()
    if file_name.endswith("folder/file2.txt"):
        return open_mock2()

open_mock = mock.mock_open()
open_mock.side_effect = open_mock_side
open_mock.return_value = None

with mock.patch('package.of.function_to_test.open', open_mock):
     function_to_test(...)

Just found another solution:

open_mock1 = mock.mock_open(read_data="file1 data")
open_mock2 = mock.mock_open(read_data="file2 data")

def open_mock_side(file_name, *args, **kwargs):
    # can be refactored to use a dict
    if file_name.endswith("folder/file1.txt"):
        return open_mock1()
    if file_name.endswith("folder/file2.txt"):
        return open_mock2()

open_mock = mock.mock_open()
open_mock.side_effect = open_mock_side
open_mock.return_value = None

with mock.patch('package.of.function_to_test.open', open_mock):
     function_to_test(...)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文