【问题标题】:Using parameters for pytest when parameters depend on each other当参数相互依赖时使用pytest的参数
【发布时间】:2023-01-03 03:06:49
【问题描述】:

我正在为类似于此的库编写 pytest 测试

from mylibrary use do_some_calculation
 
def test_df_against_angle():
    df=load_some_df()
    angle=30
    result=do_some_calculation(df,angle)
    assertTrue(result)

现在您可以看到该测试仅适用于特定数据帧和角度(30)

我必须对几个数据帧和几个角度进行测试 更复杂的是,我应该为每个数据集使用不同的角度

所以我必须测试一下

  • 对于 data_set1.csv,我必须尝试角度 0,30,60
  • 对于 data_set2.csv,我必须尝试角度 90,120,150
  • 对于 data_set3.csv,我必须尝试角度 180,210,240

所以我猜我必须为此使用 pytest 的参数。 我知道如何将简单值作为参数,(例如,我知道如何放置参数以便使用这三个 csv 文件,甚至如何将它们放入 json 文件并读取它以进入测试)但我在丢失了如何放置几种类型的参数以及这些参数取决于其他参数

理想情况下,我也想把它放在conftest.py

有人可以给我一些关于如何做到这一点的指示吗?

【问题讨论】:

标签: python pytest


【解决方案1】:

您可以使用 pytest.mark.parametrize 装饰器来参数化多个参数。例如,如果您的测试函数将文件名(CSV 文件的路径)和角度列表作为输入,您可以这样写:

@pytest.mark.parametrize("filename,angles", (
  ("data_set1.csv", (0, 30, 60)),
  ("data_set2.csv", (90, 120, 150)),
  ("data_set3.csv", (180, 210, 240)),
))
def test_df_against_angle(filename, angles):
  df = load_some_df(filename)
  ...

鉴于您在 cmets 中留下的新信息,您可以像这样编写测试以获得所需的九个参数化测试:

import pytest

from itertools import product


@pytest.mark.parametrize(
    "filename,angle",
    (
        *product(("data_set1.csv",), (0, 30, 60)),
        *product(("data_set2.csv",), (90, 120, 150)),
        *product(("data_set3.csv",), (180, 210, 240)),
    ),
)
def test_angles(filename, angle):
    assert True

这将运行以下测试:

$ pytest -v
========================================== test session starts ==========================================
platform linux -- Python 3.11.1, pytest-7.2.0, pluggy-1.0.0 -- /home/lars/.local/share/virtualenvs/python-LD_ZK5QN/bin/python
cachedir: .pytest_cache
rootdir: /home/lars/tmp/python
collected 9 items

test_angles.py::test_angles[data_set1.csv-0] PASSED                                               [ 11%]
test_angles.py::test_angles[data_set1.csv-30] PASSED                                              [ 22%]
test_angles.py::test_angles[data_set1.csv-60] PASSED                                              [ 33%]
test_angles.py::test_angles[data_set2.csv-90] PASSED                                              [ 44%]
test_angles.py::test_angles[data_set2.csv-120] PASSED                                             [ 55%]
test_angles.py::test_angles[data_set2.csv-150] PASSED                                             [ 66%]
test_angles.py::test_angles[data_set3.csv-180] PASSED                                             [ 77%]
test_angles.py::test_angles[data_set3.csv-210] PASSED                                             [ 88%]
test_angles.py::test_angles[data_set3.csv-240] PASSED                                             [100%]

=========================================== 9 passed in 0.01s ===========================================

【讨论】:

  • 谢谢!出于某种原因,它不起作用,但是当我将其更改为from pytest import mark然后@mark.parametrize("filename,angles", ( 时,它运行良好。我还必须注意文件的相对路径
  • 只有一个警告:有了这个我得到了三个测试,第一个带有data_set1.csv和一个元组(0,30,60)。理想情况下我正在寻找的是有九个测试,第一个处理data_set1.csv和0,第二个具有相同的 df 和 30 等。
  • 我想知道是否唯一的解决办法是为每个参数重复三次文件名@mark.parametrize("filename,angle", ( ("./test/data/data_1.csv", 0),("./test/data/data_1.csv", 30),("./test/data/data_1.csv", 60) ....
【解决方案2】:

我们可以写一个函数来生成所有的测试用例:

import pytest


def load_df(filename):
    # TODO: Implement this
    return f"df_{filename}"


def do_some_calculation(df, angle):
    # TODO: Implement this
    return True


def generate_test_data():
    test_combinations = [
        ("data_set1.csv", [0, 30, 60]),
        ("data_set2.csv", [90, 120, 150]),
        ("data_set3.csv", [180, 210, 240]),
    ]

    for filename, angles in test_combinations:
        df = load_df(filename)
        for angle in angles:
            yield df, angle


@pytest.mark.parametrize("df,angle", generate_test_data())
def test_df_against_angle(df, angle):
    result = do_some_calculation(df, angle)
    assert result

输出

test_combinations.py::test_df_against_angle[df_data_set1.csv-0] PASSED
test_combinations.py::test_df_against_angle[df_data_set1.csv-30] PASSED
test_combinations.py::test_df_against_angle[df_data_set1.csv-60] PASSED
test_combinations.py::test_df_against_angle[df_data_set2.csv-90] PASSED
test_combinations.py::test_df_against_angle[df_data_set2.csv-120] PASSED
test_combinations.py::test_df_against_angle[df_data_set2.csv-150] PASSED
test_combinations.py::test_df_against_angle[df_data_set3.csv-180] PASSED
test_combinations.py::test_df_against_angle[df_data_set3.csv-210] PASSED
test_combinations.py::test_df_against_angle[df_data_set3.csv-240] PASSED

笔记

  • generate_test_data 函数只加载 df 一次,它在角度之间共享。注意不要在测试之间更改 df
  • 我们在generate_test_data 函数中加载df,从而使测试无需执行设置部分。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-25
    • 2020-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多