【问题标题】:Creating PyTest fixture parameters dynamically from another fixture从另一个夹具动态创建 PyTest 夹具参数
【发布时间】:2020-06-04 21:24:54
【问题描述】:

我有一个 AWS S3 目录,其中包含几个 JSON 文件,用作测试输入。

我创建了一个 PyTest 模块,它使用模块范围 fixture 下载所有 JSON 文件一次,然后运行几个测试函数 - 每个函数都在 JSON 集上进行参数化:

import pytest
import os
from tempfile import mkdtemp, TemporaryDirectory
from glob import glob

JSONS_AWS_PATH = 's3://some/path/'

def download_jsons():
    temp_dir = mkdtemp()
    aws_sync_dir(JSONS_AWS_PATH, temp_dir)
    json_filenames = glob(os.path.join(local_path, "*.json"))
    return json_filenames

@pytest.fixture(scope='module', params=download_jsons()) #<-- Invoking download_jsons() directly
def json_file(request):
    return request.param

def test_something(json_file):
   # Open the json file and test something

def test_something_else(json_file):
   # Open the json file and test something else

def test_another_thing(json_file):
   # you got the point...

这个测试模块本身就可以工作——唯一的痛点是如何在模块\会话结束时清理temp_dir
由于download_jsons() 被直接调用,所以在json_file 夹具甚至启动之前 - 它没有自己的上下文。所以在所有测试完成后我不能让它干净temp_dir

我想让download_jsons() 本身成为一个模块\会话范围fixture。比如:

fixture(scope='module')
def download_jsons():
   temp_dir = mkdtemp()
   # Download and as glob, as above
   yield json_filenames
   shutil.rmtree(temp_dir)

fixture(scope='module')
def download_jsons(tmpdir_factory):
    #...

正如@Gabriela Melo 所建议的那样。

问题是如何使json_file 夹具参数化在download_jsons() 返回的列表上,而不直接调用它?

我尝试使用 mark.parametrizesetup_module()pytest_generate_tests(metafunc) 来实现此解决方案 - 但无法实现我正在寻找的确切功能。

【问题讨论】:

  • 您是否有关于使用夹具作为参数化参数的问题?这不受支持,请参阅issue #349。还是只是清理临时目录?这可以通过多种方式轻松完成,无需将代码放在额外的夹具中。
  • 谢谢!我错过了那个问题。很高兴知道不支持。我的问题是如何在第一次评估 json_load() 夹具之前创建临时目录,以便可以在临时目录的内容上对其进行参数化。然后我需要在 last 调用夹具之后删除 tempdir(它被多个测试函数多次使用)。我找不到这样做的方法。
  • 这甚至可能超出单个 module - 我可能需要在每个会话中下载一次 JSON,在 tempdir 的内容上对来自不同模块的测试进行参数化,然后在会话结束时删除该目录.

标签: python pytest fixtures


【解决方案1】:

这似乎就是您要查找的内容:https://docs.pytest.org/en/latest/tmpdir.html#the-tmpdir-factory-fixture

(使用 Pytest 的 tmpdir_factory 夹具并将 json_file 函数的范围设置为 session 而不是 module

【讨论】:

  • 我也试过了——但这似乎不是正确的解决方案。由于json_file 正在由download_json() 参数化 - download_json() 中的代码甚至在夹具开始之前运行。所以我无法在json_file() 中定义目录(即使它是会话范围)。此外,根据pytest documentation - 如果一个夹具被参数化,它可能会运行不止一次,即使它在session 范围内(我已经添加了打印并验证了这一点)。
  • 本质上-我需要download_json 本身就是一个固定装置,所以它可以将tmpdir_factory 作为输入-但是我找不到一种方法使它成为@ 的参数化函数987654334@.
  • 感谢您的回答!它帮助我更好地表达了这个问题,这实际上不是关于 tempdir 的创建,而是如何使用另一个夹具参数化一个夹具。我已经相应地编辑了问题。
【解决方案2】:

如果您想使用资源进行参数化,它不能由夹具返回(至少对于当前版本的pytest)。但是,您可以将设置/拆卸代码移出挂钩 - 这也将通过 pytest_generate_tests 挂钩启用参数化。示例:在项目的根目录中,创建一个名为 conftest.py 的文件,其内容如下:

from tempfile import TemporaryDirectory
from pathlib import Path


def pytest_sessionstart(session):
    # this is where we create the temp dir and download the files
    session.config._tempdir = TemporaryDirectory()
    d = session.config._tempdir.name
    aws_sync_dir(JSONS_BLOBBY_PATH, d)
    session.config._json_files = Path(d).glob("*.json")


def pytest_sessionfinish(session):
    # this is where we delete the created temp dir
    session.config._tempdir.cleanup()


def pytest_generate_tests(metafunc):
    if "file" in metafunc.fixturenames:
        # parametrize the file argument with the downloaded files
        files = metafunc.config._json_files
        metafunc.parametrize("file", files)

您现在可以像往常一样在测试中使用file 参数,例如

def test_ends_with_json(file):
    assert file.suffix == ".json"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-13
    • 1970-01-01
    相关资源
    最近更新 更多