模拟 unlink() 时检查 Path-object 的值
Check the value of Path-object when mocking unlink()
我的生产代码采用一个 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" !!!
我试图定义一个 side_effect
并模拟 Path
对象本身(使用 wraps
)但无济于事。
但我发现 并且工作正常!
可以用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 but from the "getting started" page 中,它没有任何链接,而是在“下一节”按钮中。我很吃惊我现在才发现它!
回到主题,现在您可以检查哪个路径被 unlink
ed,您会注意到您的 productive_code
实现是错误的:您假设调用 with_suffix
两次会连接两者,但事实并非如此,根据 the doc :
Return a new path with the suffix changed.
本质上:
>>> 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 :
Mocking system calls, especially those with side effects (mkdir()), is difficult and error prone.
[...]
If you really need to mock the filesystem part, I would suggest using an existing library such as pyfakefs, although I have never had such a need.
如果您的测试代码出现严重错误,您可能会损坏您的系统(取消链接不应该的文件)。
PS:不错的最小可重现示例 :)
我的生产代码采用一个 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" !!!
我试图定义一个 side_effect
并模拟 Path
对象本身(使用 wraps
)但无济于事。
但我发现
可以用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 but from the "getting started" page 中,它没有任何链接,而是在“下一节”按钮中。我很吃惊我现在才发现它!
回到主题,现在您可以检查哪个路径被 unlink
ed,您会注意到您的 productive_code
实现是错误的:您假设调用 with_suffix
两次会连接两者,但事实并非如此,根据 the doc :
Return a new path with the suffix changed.
本质上:
>>> 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 :
Mocking system calls, especially those with side effects (mkdir()), is difficult and error prone. [...] If you really need to mock the filesystem part, I would suggest using an existing library such as pyfakefs, although I have never had such a need.
如果您的测试代码出现严重错误,您可能会损坏您的系统(取消链接不应该的文件)。
PS:不错的最小可重现示例 :)