在Python中生成py.test测试
先问问题,感兴趣的话再看解释。
在使用py.test的情况下,我该如何从一小部分测试函数模板生成大量的测试函数呢?
就像这样:
models = [model1,model2,model3]
data_sets = [data1,data2,data3]
def generate_test_learn_parameter_function(model,data):
def this_test(model,data):
param = model.learn_parameters(data)
assert((param - model.param) < 0.1 )
return this_test
for model,data in zip(models,data_sets):
# how can py.test can see the results of this function?
generate_test_learn_parameter_function(model,data)
解释:
我写的代码是用来处理一个模型结构、一些数据,并学习模型的参数。所以我的单元测试包括一堆模型结构和预先生成的数据集,然后对每个结构和数据进行大约5个机器学习任务的测试。
如果我手动编写这些测试,就需要为每个模型和每个任务写一个测试。每当我想出一个新模型时,就得复制粘贴这5个任务,还得改动我指向的结构和数据。这让我觉得这样做不太好。理想情况下,我希望有5个模板函数来定义我的5个任务,然后只需为我指定的模型列表生成测试函数。
我在网上搜索,发现要么是a) 工厂模式,要么是b) 闭包,这两者让我感到困惑,并让我觉得应该有更简单的方法,因为这个问题应该是很多程序员都会遇到的。那么,真的有吗?
编辑:这是解决这个问题的方法!
def pytest_generate_tests(metafunc):
if "model" in metafunc.funcargnames:
models = [model1,model2,model3]
for model in models:
metafunc.addcall(funcargs=dict(model=model))
def test_awesome(model):
assert model == "awesome"
这将把 test_awesome
测试应用到我模型列表中的每个模型上!谢谢 @dfichter!
(注意:那个断言总是会通过,顺便说一下)
3 个回答
1
现在最简单的解决办法就是使用 pytest.mark.parametrize 这个功能:
@pytest.mark.parametrize('model', ["awesome1", "awesome2", "awesome3"])
def test_awesome(model):
assert model.startswith("awesome")
8
你也可以使用参数化的固定装置来实现这个功能。简单来说,hooks是一个用来为Py.test构建插件的接口,而参数化的固定装置是一种通用的方法,可以让你创建一个固定装置,输出多个值,并为这些值生成额外的测试案例。
插件通常是一些在整个项目(或包)中都能用的功能,而不是针对某个特定测试案例的功能。参数化的固定装置正是用来为测试案例参数化某些资源所需要的。
所以你的解决方案可以改写成这样:
@pytest.fixture(params=[model1, model2, model3])
def model(request):
return request.param
def test_awesome(model):
assert model == "awesome"
20
很好的直觉。py.test
确实支持你所说的功能,它有一个叫 pytest_generate_tests()
的钩子。你可以在 这里 找到详细的解释。