我是新的参数化和装置,仍在学习。我找到了一些使用间接参数化的帖子,但是我很难根据代码中的内容来实现。如果您能告诉我如何做到这一点,我将不胜感激
我的conftest.py中有几个fixture,它们为测试文件中的函数“get_fus_output()”提供输入文件。该函数处理输入并生成两个数据帧,以便在我的测试中进行比较。此外,我将根据一个公共值(“Fus_id”)将这两个DF转包,以分别测试它们。因此,这个函数的输出将是[(真值_df1,test _df1),(真值_df2,test _df2)…]只是为了参数化这些测试和真值df的测试。不幸的是,我不能在我的测试函数“test\u annotation\u match”中使用它,因为这个函数需要一个fixture
我无法将夹具作为输入输入输入到另一个夹具以进行参数化。是的,pytest不支持它,但无法找到间接参数化的解决方法
#fixtures from conftest.py
@pytest.fixture(scope="session")
def test_input_df(fixture_path):
fus_bkpt_file = os.path.join(fixture_path, 'test_bkpt.tsv')
test_input_df= pd.read_csv(fus_bkpt_file, sep='\t')
return test_input_df
@pytest.fixture
def test_truth_df(fixture_path):
test_fus_out_file = os.path.join(fixture_path, 'test_expected_output.tsv')
test_truth_df = pd.read_csv(test_fus_out_file, sep='\t')
return test_truth_df
@pytest.fixture
def res_path():
return utils.get_res_path()
#test script
@pytest.fixture
def get_fus_output(test_input_df, test_truth_df, res_path):
param_list = []
# get output from script
script_out = ex_annot.run(test_input_df, res_path)
for index, row in test_input_df.iterrows():
fus_id = row['Fus_id']
param_list.append((get_frame(test_truth_df, fus_id), get_frame(script_out, fus_id)))
# param_list eg : [(Truth_df1, test_df1),(Truth_df2, test_df2)...]
print(param_list)
return param_list
@pytest.mark.parametrize("get_fus_output", [test_input_df, test_truth_df, res_path], indirect=True)
def test_annotation_match(get_fus_output):
test, expected = get_fusion_output
assert_frame_equal(test, expected, check_dtype=False, check_like=True)
#OUTPUT
================================================================================ ERRORS ================================================================================
_______________________________________________________ ERROR collecting test_annotations.py
_______________________________________________________
test_annotations.py:51: in <module>
@pytest.mark.parametrize("get_fus_output", [test_input_df, test_truth_df, res_path], indirect=True)
E NameError: name 'test_input_df' is not defined
======================================================================= short test summary info ========================================================================
ERROR test_annotations.py - NameError: name 'test_input_df' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
=========================================================================== 1 error in 1.46s ===========================================================================
我不能百分之百肯定我理解你在这里要做什么,但我认为你对参数化和装置作用的理解是错误的。看起来您正试图使用fixture为测试创建参数列表,但这并不是正确的方法(正如您所看到的,您这样做肯定不起作用)
为了充分解释如何解决这个问题,首先,让我介绍一下参数化和固定装置的使用背景
参数化
我不认为这里有什么新东西,但只是为了确保我们在同一页上:
通常,在Pytest中,一个
test_*
函数就是一个测试用例:如果要使用不同的数据执行相同的测试,可以编写单独的测试:
这并不好,因为它违反了DRY原则。参数化是解决这个问题的方法。通过提供测试参数列表,可以将一个测试用例转换为多个测试用例:
固定装置
fixture也是关于DRY代码的,但方式不同
假设您正在编写一个web应用程序。您可能有几个测试需要连接到数据库。您可以在每个测试中添加相同的代码以打开和设置测试数据库,但这肯定是重复您自己的操作。比如说,如果您切换数据库,那么需要更新大量的测试代码
fixture是允许您进行一些设置(以及可能的拆卸)的功能,可用于多个测试:
修复代码
好的,有了这些背景,让我们深入研究一下你的代码
第一个问题是
@pytest.mark.parametrize
装饰器:这不是使用} 只是参数化装置的另一种方法。这与你想要的完全不同
indirect
的正确情况。就像测试可以参数化一样,fixtures can be parameterized。从文档中不太清楚(在我看来),但是^{事实上,对于
get_fus_output
要使用test_input_df
、test_truth_df
和res_path
装置,根本不需要@pytest.mark.parametrize
行。一般来说,如果测试函数或fixture的任何参数未被其他方式使用(例如由@pytest.mark.parametrize
装饰器使用),则它将自动假定为fixture因此,您现有的
@pytest.mark.parametrize
没有达到您期望的效果。那么您如何参数化您的测试呢?这是一个更大的问题:您正试图使用get_fus_output
fixture为test_annotation_match
创建参数这不是你可以用固定装置做的事情。当Pytest运行时,首先它收集所有的测试用例,然后它逐个运行它们。测试参数必须在收集阶段准备好,但夹具直到测试阶段才运行。夹具中的代码无法帮助进行参数化。您仍然可以通过编程方式生成参数,但设备不是这样做的方式
您需要做几件事:
首先,将}和
get_fus_output
从fixture转换为常规函数。这意味着删除@pytest.fixture
装饰器,但您还必须更新它,以避免使用test_input_df
{res_path
固定装置。(如果没有其他东西需要它们作为固定装置,您可以将它们全部转换为常规函数,在这种情况下,您可能希望将它们放在conftest.py
之外的自己的模块中,或者只是将它们移动到相同的测试脚本中。)然后,
@pytest.mark.parametrize
需要使用该函数来获取参数列表:相关问题 更多 >
编程相关推荐