【问题标题】:How to test a function that uses the same path for finding and creating files so it'll create in a temporary dir?如何测试使用相同路径查找和创建文件的函数,以便在临时目录中创建?
【发布时间】:2021-08-31 13:36:47
【问题描述】:

我想使用 Pytest 为函数编写测试。该函数获取一个 id,通过该 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

【问题讨论】:

  • find_local_dir 返回什么?原始字符串?或者是其他东西?你能分享一下它的实现吗?
  • @NielGodfreyPonciano 我刚刚编辑了问题

标签: python pytest temporary-files


【解决方案1】:

我在测试目录中有一个视频,我想用它来测试

所以我假设您已经有一个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/被删除了。

【讨论】:

  • 谢谢!澄清一下,1. test_pipeline.py 也在tests 中。 2. 测试结束后目录'foo'会被删除吗?
  • 我更新了答案。我在测试中移动了 test_pipeline.py。然后为了便于测试,所有临时文件都将在tests/tmp 中,然后在测试结束时将其删除(不删除任何预先存在的测试文件)。你能检查一下这是否适合你的需要吗?
  • 抱歉,它成功了!!但是像你展示的那样我自己定义tmp_path会改变tmp_path以进行其他测试吗?
  • 除非您明确修补 monkeypatch.setattr(pipeline, 'find_local_dir', mock),其中 mock 包含 tmp_path,否则它不会自动反映其他测试。如果您希望它自动反映,您可能有兴趣将其放在带有标志 autouse=True 的 pytest 固定装置中。
猜你喜欢
  • 2021-03-24
  • 2011-03-14
  • 1970-01-01
  • 1970-01-01
  • 2016-02-14
  • 1970-01-01
  • 2010-10-11
  • 1970-01-01
相关资源
最近更新 更多