使用 tmp_path fixture 创建后路径不存在

path does not exist after being created with tmp_path fixture

编辑:这是一个 git 便于测试的回购协议:

https://gitlab.com/qualisign/ugit-bdd/

我想将一些重复代码从 step_def 文件重构到 conftest.py 文件。这是 step_def 的样子:

@scenario('../features/CLI.feature',
          'store file in object database')

def test_file_stored_by_content_address():
    pass

@given("a file exists at some full path within a ugit dir", target_fixture="file_exists_at_path")
def file_exists_at_path(file_within_ugit_dir):
    return file_within_ugit_dir

@when("I enter ugit hash-object followed by that path")
def file_gets_hashed(file_exists_at_path):
    dir_name = os.path.dirname(file_exists_at_path)
    base_name = os.path.basename(file_exists_at_path)
    os.chdir(dir_name)
    os.system(f'ugit hash-object {base_name}')

@then("this object is stored in a content-addressed location in the subdirectory .ugit/objects")
def object_saved_in_db(file_within_ugit_dir, file_hashed):
    with open(file_hashed, "rb") as f:
        contents = f.read()
        with open(file_path, "rb") as hf:
            assert hf.read() == f.read()

这里是 conftest.py:

import os
import subprocess
import hashlib
import pytest
from pytest_bdd import scenario, given, when, then, parsers

WISE_WORDS = "Don\'t be a fool!  I\'ll call you later."

@pytest.fixture(scope="session")
def is_ugit_dir(tmp_path_factory):
    path = tmp_path_factory.mktemp('data')
    os.chdir(path)
    subprocess.run(['ugit', 'init'])
    return path

@pytest.fixture
def file_within_ugit_dir(is_ugit_dir):
    path = is_ugit_dir
    full_path = f'{path}/wise_words.txt'
    os.system(f'echo {WISE_WORDS} > wise_words.txt')
    return full_path


   
 @pytest.fixture
def file_hashed(is_ugit_dir, file_within_ugit_dir):
    """
    Returns the full path to a hash-object within the objects database
    """
    subprocess.run(['ugit', 'hash-object', file_within_ugit_dir])
    # there should now be a file with a sha1 content-address in the following directory
    objects_dir = os.path.dirname(is_ugit_dir)+'/.ugit/objects/'
    with open(file_within_ugit_dir, "rb") as f:
        # first calculate the hash
        sha_hash = hashlib.sha1 (f.read()).hexdigest ()
        return objects_dir+sha_hash

当我 运行 测试时,临时目录似乎没有在步骤之间保持打开状态:

t-74/.ugit/objects/7b5ee3d8d42c66048125a3937a0170ffdaf7b272'

    @then("this object is stored in a content-addressed location in the subdirectory .ugit/objects")
    def object_saved_in_db(file_hashed):
>       with open(file_hashed, "rb") as f:
E       FileNotFoundError: [Errno 2] No such file or directory: '/private/var/folders/m2/99x5jvw95ll6sbtgvj5md9700000gp/T/pytest-of-davidjoseph/pytest-74/.ugit/objects/7b5ee3d8d42c66048125a3937a0170ffdaf7b272'

/Users/davidjoseph/projects/ugit-bdd/tests/step_defs/test_cli.py:43: FileNotFoundError
-------------------------------------- Captured stdout call ---------------------------------------
Initialized empty ugit repository in /private/var/folders/m2/99x5jvw95ll6sbtgvj5md9700000gp/T/pytest-of-davidjoseph/pytest-74/data1/.ugit
7b5ee3d8d42c66048125a3937a0170ffdaf7b272

有什么方法可以让这个临时目录保持打开状态,以便在 conftest.py 文件中的固定装置之间重复使用,并最终在 step_def 文件中重复使用?

我会说你的代码有逻辑问题。 根据测试场景,fixture file_hashed 必须 return 包含哈希的 existing 文件的路径。可以在这里看到:

@then("this object is stored in a content-addressed location in the subdirectory .ugit/objects")
def object_saved_in_db(file_within_ugit_dir, file_hashed):
    with open(file_hashed, "rb") as f:
        contents = f.read()
        with open(file_path, "rb") as hf:
            assert hf.read() == f.read()

conftest.py 中,您没有创建包含哈希的文件。您正在创建一个虚拟 link,并且由于 link 上没有任何内容,您会得到 FileNotFoundError。错误在这里(您的代码没有创建哈希文件):

@pytest.fixture
def file_hashed(is_ugit_dir, file_within_ugit_dir):
    objects_dir = os.path.dirname(is_ugit_dir)+'/.ugit/objects/'
    with open(file_within_ugit_dir, "rb") as f:
        # first calculate the hash
        sha_hash = hashlib.sha1 (f.read()).hexdigest ()
        return objects_dir+sha_hash

按照评论中的建议将 is_ugit_dir fixture 的范围更改为 "session" 就足够了;其余都是你自己代码的错误:

  1. path = tmp_path_factory.mktemp('data')
    os.chdir(path)
    subprocess.run(['ugit', 'init'])
    

    您将当前工作目录更改为 /tmp/pytest-smth/data 并在其中调用 ugit init - 我假设该工具随后会在 /tmp/pytest-smth/data/.ugit 处创建存储库元数据。稍后,您使用

    objects_dir = os.path.dirname(is_ugit_dir)+'/.ugit/objects/'
    

    创建对象目录 - 这将使您 /tmp/pytest-smth/.ugit/objects。难怪这个目录不存在。将其更改为例如objects_dir = is_ugit_dir / '.ugit' / 'objects' 修复了第一个错误。作为后续行动,必须将 file_hashed 夹具的 return 更改为 objects_dir / sha_hash 以使用 pathlib 路径。

  2. contents = f.read()
    with open(file_path, "rb") as hf:
        assert hf.read() == f.read()
    

    除了 file_path 未定义(我猜这应该是 file_within_ugit_dir),您正在将文件读入 contents 然后再读一次。为什么?在再次调用 f.read() 之前通过 f.seek(0) 倒回文件,或者使用 contents 进行比较。

这是完整的工作代码,只进行了最少的必要更改:

conftest.py

import os
import subprocess
import hashlib
import pytest
from pytest_bdd import scenario, given, when, then, parsers

WISE_WORDS = "Don\'t be a fool!  I\'ll call you later."


@pytest.fixture(scope="session")
def is_ugit_dir(tmp_path_factory):
    path = tmp_path_factory.mktemp('data')
    os.chdir(path)
    subprocess.run(['ugit', 'init'])
    return path


@pytest.fixture
def file_within_ugit_dir(is_ugit_dir):
    path = is_ugit_dir
    full_path = path / 'wise_words.txt'
    os.system(f'echo {WISE_WORDS} > wise_words.txt')
    return full_path


@pytest.fixture
def file_hashed(is_ugit_dir, file_within_ugit_dir):
    """
    Returns the full path to a hash-object within the objects database
    """
    subprocess.run(['ugit', 'hash-object', file_within_ugit_dir])
    # there should now be a file with a sha1 content-address in the following directory
    objects_dir = is_ugit_dir / '.ugit' / 'objects'
    with open(file_within_ugit_dir, "rb") as f:
        # first calculate the hash
        data = b'blob\x00' + f.read()  # prepend the object type
        sha_hash = hashlib.sha1(data).hexdigest()
        return objects_dir / sha_hash

step_def.py

import os
from pytest_bdd import scenario, given, when, then, parsers


@scenario('features/CLI.feature', 'store file in object database')
def test_file_stored_by_content_address():
    pass


@given("a file exists at some full path within a ugit dir", target_fixture="file_exists_at_path")
def file_exists_at_path(file_within_ugit_dir):
    return file_within_ugit_dir


@when("I enter ugit hash-object followed by that path")
def file_gets_hashed(file_exists_at_path):
    dir_name = os.path.dirname(file_exists_at_path)
    base_name = os.path.basename(file_exists_at_path)
    os.chdir(dir_name)
    os.system(f'ugit hash-object {base_name}')

@then("this object is stored in a content-addressed location in the subdirectory .ugit/objects")
def object_saved_in_db(file_within_ugit_dir, file_hashed):
    with open(file_hashed, "rb") as f:
        contents = f.read().strip(b"blob\x00")
        with open(file_within_ugit_dir, "rb") as hf:
            assert hf.read() == contents