我想在参数化参数中使用一个名为“time_period”的装置。该装置返回一个 TimePeriod 对象,该对象存储 2 个日期“开始”和“结束”。我需要编写一个测试来检查我的函数“filter_data_by_time_horizon”是否删除了 pyspark 数据帧中给定时间段之外的所有行。为此,我想参数化我的测试以覆盖所有边缘情况:
@pytest.mark.parametrize("date_from, date_to", [
(time_period.start - relativedelta(days=4), time_period.start - relativedelta(days=2)),
(time_period.end + relativedelta(days=4), time_period.end + relativedelta(days=2)),
])
def test_filter_data_by_time_horizon(factory, date_from, date_to):
test_data = filter_data_by_time_horizon(factory_batch_to_dataframe(factory.create_batch(
size=2,
date_from=date_from,
date_to=date_to,
)))
assert test_data.count() == 0
但是我无法按照我在代码中编写的方式使用 time_period 固定装置。我可以从技术上将其声明为测试用例之外的变量,但这似乎不是一个干净的解决方案。顺便说一句,time_period 固定装置存储在模块范围conftest.py 中。 我该如何干净利落地处理它?
您可以创建一个间接夹具,在返回您将在测试函数中使用的参数之前进行计算。这是一个未经测试的草稿,应该可以让您了解如何处理它:
from functools import reduce
from operator import add, sub
@pytest.fixture()
def time_horizon(time_period, request):
tp = getattr(time_period, request.param[0])
tp_from = reduce(request.param[1], (tp, relativedelta(days=request.param[3])))
tp_to = reduce(request.param[1], (tp, relativedelta(days=request.param[5])))
return (tp_from, tp_to)
@pytest.mark.parametrize("time_horizon", [('start', sub, 4, 2), ('end', add, 4, 2)], indirect=True)
def test_filter_data_by_time_horizon(time_horizon, factory):
test_data = filter_data_by_time_horizon(factory_batch_to_dataframe(factory.create_batch(
size=2,
date_from=time_horizon[0],
date_to=time_horizon[1],
)))
assert test_data.count() == 0
参数化中的关键元素是
indirect=True
,它会导致调用 time_horizon
夹具,而夹具中的 request.param
则允许您访问可变参数。