如何测试使用相同路径查找和创建文件的函数,以便它在临时目录中创建?

How to test a function that uses the same path for finding and creating files so it'll create in a temporary dir?

我想使用 Pytest 为函数编写测试。该函数获取一个 id,通过它找到视频文件的路径,然后在视频文件夹中创建另一个文件夹(将一些新文件放入其中)。这是函数:

def foo(id):
    root_dir = find_local_dir(id) # finds the path to the video file 
    video_file = root_dir / 'video.mp4'
    out_dir = root_dir / 'foo'
    out_dir.mkdir(parents=True, exist_ok=True)

我在tests目录下有一个视频,我想用它来测试,我使用monkeypatch来防止函数根据id寻找视频。但我不知道如何让它在 tests 中获取视频并在 tmp 中创建新文件夹,不更改 foo.

我试图将视频从 tests 复制到 tmp_path,但这不起作用:

def test_foo(tmp_path, monkeypatch):
    id = '1234'

    mock = MagicMock()
    mock.return_value = tmp_path
    monkeypatch.setattr(pipeline, 'find_local_dir', mock)
    
    copy2('coffee.mp4', tmp_path / 'video.mp4')

    var = pipeline.foo(id)

我的错误是FileNotFoundError: [WinError 2] The system cannot find the file specified

我猜复制没有成功? (我对 Pytest 有点陌生,所以我不知道这是否可行。)

我很乐意用任何其他方法来解决这个问题而不改变 foo

谢谢。

编辑:

def find_local_dir(id):
    local_dir = Path(f'/tmp/{id}')
    local_dir.mkdir(parents=True, exist_ok=True)
    return local_dir

I have a video in the tests directory which I would like to use for testing

所以我假设您已经有一个 tests 目录,我们可以将其用作测试的临时目录。现在,我们需要控制的只是 find_local_dir() 的输出指向 tests 目录,因为

  • 这是video.mp4所在的地方
  • 这是创建目录 foo 的地方

文件树

$ tree 
.
├── pipeline.py
└── tests
    ├── coffee.mp4
    └── test_pipeline.py

pipeline.py

from pathlib import Path


def find_local_dir(id):
    local_dir = Path(f'/tmp/{id}')
    local_dir.mkdir(parents=True, exist_ok=True)
    return local_dir


def foo(id):
    root_dir = find_local_dir(id) # finds the path to the video file 
    video_file = root_dir / 'video.mp4'
    out_dir = root_dir / 'foo'
    out_dir.mkdir(parents=True, exist_ok=True)

    # Let's add a print to see the location of the video file
    print(f"{video_file=}")

test_pipeline.py

import os
from pathlib import Path
from shutil import copy2, rmtree
import time
from unittest.mock import MagicMock

import pytest

import pipeline


@pytest.fixture
def tmp_path(mocker):
    local_dir = Path(f'./tests/tmp')
    local_dir.mkdir(parents=True, exist_ok=True)

    yield local_dir

    # Optionally, delete the temporary directory used for testing
    rmtree(local_dir)


def test_foo(tmp_path, monkeypatch):
    id = '1234'

    mock = MagicMock()
    mock.return_value = tmp_path
    monkeypatch.setattr(pipeline, 'find_local_dir', mock)

    copy2('./tests/coffee.mp4', tmp_path / 'video.mp4')

    pipeline.foo(id)

    # Remove this line. It is just here so that we can see the files before deletion.
    time.sleep(10)

运行 测试

$ pytest -q -rP
                                                                                                            
================================================================================================= PASSES ==================================================================================================
________________________________________________________________________________________________ test_foo _________________________________________________________________________________________________
------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
video_file=PosixPath('tests/tmp/video.mp4')
1 passed in 0.05s

测试进行时的文件树

$ tree
.
├── pipeline.py
└── tests
    ├── coffee.mp4
    ├── test_pipeline.py
    └── tmp
        ├── foo
        └── video.mp4

测试完成后的文件树

$ tree
.
├── pipeline.py
└── tests
    ├── coffee.mp4
    └── test_pipeline.py

如您所见,视频文件的位置是正确的 tests/tmp/video.mp4。新目录也在 tests/tmp/foo 处正确创建。然后在测试结束的时候,临时的tests/tmp/被删除了