【问题标题】:Check the value of Path-object when mocking unlink()模拟 unlink() 时检查 Path-object 的值
【发布时间】:2022-02-01 21:26:54
【问题描述】:

我的生产代码采用pathlib.Path 实例并创建第二个带有修改后缀的实例,如果存在则删除第二个文件。

def productive_code(fp):
    # "foo" + ".wrong" + ".csv" = "foo.wrong.csv"
    fp.with_suffix('.wrong{}'.format(fp.suffix))
    
    fp_wrong.unlink(missing_ok=True)  # >= Python3.8

在单元测试中,我修补了pathlib.Path.unlink(),我可以检查它是否被调用以及使用了哪些参数。

但是如何检查路径对象本身的“值”呢?我想测试“第二个”文件名是否正确创建。

import unittest
from unittest import mock
import pathlib

    class TestMy(unittest.TestCase):
        @mock.patch('pathlib.Path.unlink')
        def test_unlink(self, mock_unlink):
            productive_code(pathlib.Path('foo.csv'))
            mock_unlink.assert_called_once_with(missing_ok=True)
            # test "foo.wrong.csv" !!!

【问题讨论】:

    标签: python unit-testing mocking python-3.8


    【解决方案1】:

    我尝试定义side_effect 并模拟Path 对象本身(使用wraps)但无济于事。

    但我找到了this answer,它工作正常!
    可以使用autospec=True

    import unittest
    from unittest import mock
    import pathlib
    
    
    def productive_code(fp):
        # "foo" + ".wrong" + ".csv" = "foo.wrong.csv"
        fp_wrong = fp.with_suffix('.wrong').with_suffix(fp.suffix)
    
        fp_wrong.unlink(missing_ok=True)  # >= Python3.8
    
    
    class TestMy(unittest.TestCase):
        @mock.patch('pathlib.Path.unlink', autospec=True)
        #                                  ^^^^^^^^^^^^^
        def test_unlink(self, mock_unlink):
            productive_code(pathlib.Path('foo.csv'))
            mock_unlink.assert_called_once_with(pathlib.Path("foo.wrong.csv"), missing_ok=True)
    

    此信息不在mock library documentation 中,而是来自"getting started" page,它在“下一部分”按钮中没有链接。我惊呆了,我现在才发现它!

    回到主题,现在您可以检查哪个路径得到unlinked,您会注意到您的productive_code 实现是错误的:您认为两次调用with_suffix 会连接两者,但事实并非如此,根据the doc

    返回更改后缀的新路径。

    本质上:

    >>> from pathlib import Path
    >>> Path("a.txt").with_suffix(".mp3")
    PosixPath('a.mp3')
    >>> Path("a.txt").with_suffix(".mp3").with_suffix(".html")
    PosixPath('a.html')
    >>> Path("a.txt.mp3.html").with_suffix(".zip")
    PosixPath('a.txt.mp3.zip')
    

    解决测试问题的另一种方法是this code review's answer

    模拟系统调用,尤其是那些具有副作用的系统调用 (mkdir()),非常困难且容易出错。 [...] 如果你真的需要模拟文件系统部分,我建议使用现有的库,比如 pyfakefs,虽然我从来没有这样的需要。

    如果您的测试代码出错,您可能会损坏您的系统(取消不应链接的文件)。

    PS:很好的最小可重现示例:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-05
      • 1970-01-01
      • 2020-03-08
      • 2017-06-29
      • 1970-01-01
      • 2012-01-17
      • 2018-04-16
      相关资源
      最近更新 更多