为什么在使用 Pyfakefs 时 Path.rename 上出现 FileNotFoundError?

Why FileNotFoundError on Path.rename while using Pyfakefs?

我为重命名文件的函数编写了一个测试,例如/videos/vid_youtube.mp4/videos/youtube/vid.mp4。测试使用 Pyfakefs 修补 fs。

当代码实际重命名文件时,出现此错误。

FileNotFoundError: [Errno 2] No such file or directory: '/home/user/code/project/test/DLV/videos/vid_youtube.mp4' -> '/home/user/code/project/test/DLV/videos/youtube/vid.mp4'

这就是我设置 fakefs 的方式

def setUp(self) -> None:
    self.setUpPyfakefs()
    self.fs.create_dir(Path(Dirs.VIDEOS))  # /home/user/code/project/test/DLV/videos
    self.fs.create_file(Path(Dirs.VIDEOS / "vid_youtube.mp4"))

正在测试的代码。

class Files:
    @staticmethod
    def rename_video_files():
        all_files = Collect.video_files()

        for files_for_type in all_files:
            for file in all_files[files_for_type]:
                path = Path(file)
                platform = Files.detect_platform(path)
                platform_dir = Path(Dirs.VIDEOS, platform)
                platform_dir.mkdir(exist_ok=True)

                new_name = path.stem.replace(f'_{platform}', '')
                new_path = Dirs.VIDEOS / platform / f'{new_name}{path.suffix}'

                old_path = Dirs.VIDEOS / path
                old_path.rename(new_path)   # throws FileNotFoundError

我调试了测试和被测方法,甚至将假 fs 传递给 rename_video_files(fakefs) 以检查文件和目录。所有文件和目录看起来都是正确的。

这里出了什么问题?

这里的问题很可能是 Dirs.VIDEOS 的静态初始化。这在加载时初始化为 pathlib.Path,并且不会在您稍后设置 pyfakefs 时进行修补(如果您在哪里使用 unittest.patch 进行修补,也会发生同样的问题) .

有两种方法可以解决这个问题:

  • 调整代码以不静态初始化路径
    这可以通过静态定义 str 路径,并在 运行 时将其转换为 Path 来完成,或者使用一种方法来获取路径而不是属性(例如 Dirs.VIDEO() 而不是 Dirs.VIDEO`).
  • 调整测试以重新加载测试代码
    如果在 pyfakefs 初始化后重新加载测试代码,它将正确修补。 pyfakefssetUpPyfakefs 中提供了一个 argument 来做到这一点:
from pyfakefs.fake_filesystem_unittest import TestCase

from my_module import video_files
from my_module.video_files import Dirs, Files


class MyTest(TestCase):
    def setUp(self) -> None:
        self.setUpPyfakefs(modules_to_reload=[video_files])
        self.fs.create_dir(
            Path(Dirs.VIDEOS))  # /home/user/code/project/test/DLV/videos
        self.fs.create_file(Path(Dirs.VIDEOS / "vid_youtube.mp4"))

(假设您的测试代码位于 my_module.video_files.py

免责声明:
我是 pyfakefs 的贡献者。