pytest测试框架使用基础05 fixture——params和ids

我们都知道参数化。
比如我要测试一个查询接口/test/get_goods_list,这个接口可以查询到商品的信息。
在请求中,我可以根据请参数goods_status的不同传值,可以查询到对应状态的商品数据,比如:1-未销售、2-销售中、3-已售罄。
那么在编写自动化测试case的时候,在断言里就要分别验证到这3种状态的商品数据。
通常,在执行case之前,会去数据库分别插入对应状态的商品数据,来满足测试需求。
而在pytest框架中,我喜欢用fixture()去实现测试数据的准备和清理工作。
于是,2种实现方式瞬间出现:

  • 写3个case,只有传参不一样。对应写3个fixture来分别初始化3种状态的商品数据。
  • 写1个case,在case里用 @pytest.mark.parametrize() 进行参数化。只写一个fixture一次性的插入3种状态的商品数据。

在这2个方法里,显然第二种更优雅,避免了case的冗余代码。
但是一把梭的插入所有的测试数据还是差点意思,如果我只想执行其中的某一个数据的case,那么其他2个不必要的数据也生成了。
所以,我想要的样子是,可以自由的根据执行的case的参数,去对应的初始化测试数据。
具体点的描述就是:参数化里3个参数,我只执行2-销售中的时候,只去插入2-销售中这一种状态的数据。
网上搜的都是简单的fixture参数化的东西,达不到我想要的需求。于是乎我自己去翻阅官方文档,发现可以用fixture中的params和ids
这2个参数去实现我的需求。

一、fixture中的params

params是一个列表,用来存放我们要参数化的值。
举例:这里的代码放了参数1和参数2 这2个参数,2个测试case,都会用params里的参数去分别执行2次。

import pytest


@pytest.fixture(params=["params1", "params2"])
def my_fixture(request):
    return request.param


def test_fixture_01(my_fixture):
    print("\n 执行test_fixture_01")
    print(my_fixture)


def test_fixture_02(my_fixture):
    print("\n 执行test_fixture_02")
    print(my_fixture)

运行一下:

============================= test session starts =============================
collecting ... collected 4 items

test_params.py::test_fixture_01[params1] 
test_params.py::test_fixture_01[params2] 
test_params.py::test_fixture_02[params1] PASSED                          [ 25%]
 执行test_fixture_01
params1
PASSED                          [ 50%]
 执行test_fixture_01
params2

test_params.py::test_fixture_02[params2] 

============================== 4 passed in 0.10s ==============================
PASSED                          [ 75%]
 执行test_fixture_02
params1
PASSED                          [100%]
 执行test_fixture_02
params2

Process finished with exit code 0

二、fixture中的ids

ids也是要结合着params一起使用的。当有多个 params 时,针对每一个 param,可以指定一个id,
然后,这个 id 会变成测试用例名字的一部分。如果没有提供 id,则 id 将自动生成。

import pytest


@pytest.fixture(params=['params1', 'params2'], ids=['id-01', 'id-02'])
def my_fixture(request):
    return request.param


def test_fixture_01(my_fixture):
    print("\n 执行test_fixture_01")
    print(my_fixture)

运行下,结果里case名称后分别带了 id:[id-01]和[id-02]

============================= test session starts =============================
collecting ... collected 2 items

test_ids.py::test_fixture_01[id-01] PASSED                               [ 50%]
 执行test_fixture_01
params1

test_ids.py::test_fixture_01[id-02] PASSED                               [100%]
 执行test_fixture_01
params2


============================== 2 passed in 0.03s ==============================

Process finished with exit code 0

三、利用ids实现需求

ids的赋值除了上述的方式之外,还有一种,也就是帮我实现需求的一种,直接看代码。

import pytest


def init_data(fixture_value):
    if fixture_value == 1:
        return "unsold"
    elif fixture_value == 2:
        return "onSale"
    elif fixture_value == 3:
        return "sellOut"


@pytest.fixture(params=[1, 2, 3], ids=init_data)
def my_method(request):
    req_params = request.param
    print("\n参数为:【{}】,执行sql--插入【{}】状态的数据".format(req_params, req_params))
    yield req_params
    print("\n执行sql--清理参数为【{}】的测试数据".format(req_params, req_params))
    print("\n--------------------------------")


def test_01(my_method):
    print("\n正在执行【{}】的case--".format(my_method))


if __name__ == '__main__':
    pytest.main(['-s', '-v', 'test_cases01.py::test_01'])

示例代码就没有去真正的写一个接口的case了,所以直接用print()打印出我要做的事儿。
上述代码中,重点就是3个部分:

  • test_01(),这是测试case
  • my_method()这是我定义的fixture函数
  • init_data()这个是用来初始化测试数据的函数
  1. test_01()
    测试case没什么说的,一般来说接口的case里的组成就是:传参、调用测试接口、断言。
    case里传入了my_method函数,这是调用fixture的一种方式。
def test_01(my_method):
    print("\n正在执行[{}]的case--".format(my_method))
  1. my_method()
    定义了my_method这个fixture去进行case执行之前的测试数据处理。
    @pytest.fixture(params=[1, 2, 3], ids=init_data)
def my_method(request):
    req_param = request.param
    print("\n参数为:{}".format(req_param))
    yield req_param
    print("\n执行sql--清理参数为【{}】的测试数据".format(req_param))
    print("\n----------------------------------------")

params=[1,2,3] 就是相当于我接口请求体里查询不同状态商品的数据对应的参数,1-未销售、2-销售中、3-已售罄。
ids 在上面单独介绍的例子中是直接赋值的,但是在这里,我是把一个函数赋给了它,这个函数就是init_data()。
当然了,为了满足后面我的指定参数执行case的需求,init_data要返回具体的id才行。

  1. init_data()

init_data(fixture_value)函数里传入的fixture_value,其实就是fixture函数里的params=[1, 2, 3]。
return出来的则是这个参数对应的id,分别是"未销售"、“销售中”、“已售罄”,
那么我就可以通过pytest命令 加上 -k来指定要运行的case。

def init_data(fixture_value):
    if fixture_value == 1:
        return "unsold"
    elif fixture_value == 2:
        return "onSale"
    elif fixture_value == 3:
        return "sellOut"

先不用-k,看下整个的运行结果。

if __name__ == '__main__':
    pytest.main(['-s', '-v', 'test_my_fixture.py::test_01'])

运行结果:

collected 3 items                                                                                                                                                            
 
test_my_fixture.py::test_01[\u672a\u9500\u552e]
参数为:【1,执行sql--插入【1】状态的数据
 
正在执行【1】的case--
PASSED
执行sql--清理参数为【1】的测试数据
 
----------------------------------------
 
test_my_fixture.py::test_01[\u9500\u552e\u4e2d]
参数为:【2,执行sql--插入【2】状态的数据
 
正在执行【2】的case--
PASSED
执行sql--清理参数为【2】的测试数据
 
----------------------------------------
 
test_my_fixture.py::test_01[\u5df2\u552e\u7f44]
参数为:【3,执行sql--插入【3】状态的数据
 
正在执行【3】的case--
PASSED
执行sql--清理参数为【3】的测试数据
 
----------------------------------------
 
 
============================================================================= 3 passed in 0.03s =============================================================================

可以看到,在case执行之前,就插入了3种状态的测试数据,并且运行了3个case。
接下来,我们用-k来执行 id是"onSale"的case:

if __name__ == '__main__':
    pytest.main(['-s', '-v', '-k', "onSale", 'test_my_fixture.py::test_01'])

运行结果:

collected 3 items / 2 deselected / 1 selected                                                                                                                                
 
test_my_fixture.py::test_01[onSale]
参数为:【2,执行sql--插入【2】状态的数据
 
正在执行【2】的case--
PASSED
执行sql--清理参数为【2】的测试数据
 
----------------------------------------
 
 
====================================================================== 1 passed, 2 deselected in 0.03s ======================================================================

可以看到,找到了3个case,但是只执行了我们制定要运行的case。
在我以前写的case中,其实并没有这样写。之前我们写了一个mock服务,于是乎我就把一些会变化的请求参数也配置进去了,然后根据我
传参的不同,去拿到我想要的请求body,最后再去请求我要测试的接口。

  • 20
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
pytest测试框架中的fixture是为了在测试过程中提供预定义的测试数据或测试环境设置。在给定的引用中,我们可以看到三个使用fixture的示例。 引用中的示例展示了一个带有fixture的测试类TestCase。其中的test4方法接受一个名为test1的fixture作为参数。在这个方法中,我们可以看到对test1的使用,并且验证了test1的值与预期值sex相等。 引用中的示例展示了一个带有fixture的测试函数test2。在这个函数中,我们可以看到test1作为一个fixture被注入到test2函数中,然后我们可以验证test1的值与预期值'leo'相等。 引用中的示例也展示了一个带有fixture的测试函数test3。与前面的示例类似,test3函数接受一个名为test1的fixture作为参数,并在函数中使用test1并验证其值与预期值name相等。 总之,pytestfixture可以用于提供测试数据或设置测试环境,并且可以在测试函数或测试类中使用。它可以帮助我们更方便地编写和组织测试代码。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [pytest框架fixture详细使用](https://blog.csdn.net/king_liuhui/article/details/122819352)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值