我们都知道参数化。

比如我要测试一个查询接口/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=['参数1', '参数2'])
def my_fixture(request):
return request.param def test_fixtures_01(my_fixture):
print('\n 执行test_fixtures_01')
print(my_fixture) def test_fixtures_02(my_fixture):
print('\n 执行test_fixtures_02')
print(my_fixture)

运行一下:

collecting ... collected 4 items

test_ids.py::test_fixtures_01[\u53c2\u65701] PASSED                      [ 25%]
执行test_fixtures_01
参数1 test_ids.py::test_fixtures_01[\u53c2\u65702] PASSED [ 50%]
执行test_fixtures_01
参数2 test_ids.py::test_fixtures_02[\u53c2\u65701] PASSED [ 75%]
执行test_fixtures_02
参数1 test_ids.py::test_fixtures_02[\u53c2\u65702] PASSED [100%]
执行test_fixtures_02
参数2 ============================== 4 passed in 0.03s ============================== Process finished with exit code 0

二、fixture中的ids

ids也是要结合着params一起使用的。当有多个 params 时,针对每一个 param,可以指定一个id

然后,这个 id 会变成测试用例名字的一部分。如果没有提供 id,则 id 将自动生成。

import pytest

@pytest.fixture(params=['参数1', '参数2'], ids=["id-01", "id-02"])
def my_fixture(request):
return request.param def test_fixtures_01(my_fixture):
print('\n 执行test_fixtures_01')
print(my_fixture)

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

collecting ... collected 2 items

test_ids.py::test_fixtures_01[id-01] PASSED                              [ 50%]
执行test_fixtures_01
参数1 test_ids.py::test_fixtures_01[id-02] PASSED [100%]
执行test_fixtures_01
参数2 ============================== 2 passed in 0.02s ============================== 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_param = request.param
print("\n参数为:【{}】,执行sql--插入【{}】状态的数据".format(req_param, req_param))
yield req_param
print("\n执行sql--清理参数为【{}】的测试数据".format(req_param, req_param))
print("\n----------------------------------------") def test_01(my_method):
print("\n正在执行【{}】的case--".format(my_method)) if __name__ == '__main__':
pytest.main(['-s', '-v', 'test_my_fixture.py::test_01'])

示例代码就没有去真正的写一个接口的case了,因为太(lan)忙了,所以直接用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))

2、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才行。

3、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,最后再去请求我要测试的接口。

现在新换了个地方,每天忙于dian业dian务dian,工作中突然有了这个想法,于是乎抽空找寻了下方法。这个方法我在后面的自动化服务搭建

中会去运用,届时有新想法再分享。

【pytest】(十)fixture参数化-巧用params和ids优雅的创建测试数据的更多相关文章

  1. pytest(6)-Fixture(固件)

    什么是固件 Fixture 翻译成中文即是固件的意思.它其实就是一些函数,会在执行测试方法/测试函数之前(或之后)加载运行它们,常见的如接口用例在请求接口前数据库的初始连接,和请求之后关闭数据库的操作 ...

  2. 『德不孤』Pytest框架 — 12、Pytest中Fixture装饰器(二)

    目录 5.addfinalizer关键字 6.带返回值的Fixture 7.Fixture实现参数化 (1)params参数的使用 (2)进阶使用 8.@pytest.mark.usefixtures ...

  3. 『德不孤』Pytest框架 — 13、Pytest中Fixture装饰器(三)

    目录 9.ids参数说明 10.name参数说明 11.scope参数说明 (1)scope="function" (2)scope="class" (3)sc ...

  4. pytest.4.Fixture

    From: http://www.testclass.net/pytest/fixture/ 我们可以简单的把Fixture理解为准备测试数据和初始化测试对象的阶段. 一般我们对测试数据和测试对象的管 ...

  5. Pytest进阶之参数化

    前言 unittest单元测试框架使用DDT进行数据驱动测试,那么身为功能更加强大且更加灵活的Pytest框架怎么可能没有数据驱动的概念呢?其实Pytest是使用@pytest.mark.parame ...

  6. pytest.9.使用fixture参数化接口入参

    From: http://www.testclass.net/pytest/test_api_using_params/ 背景 接上一节v2ex网站的查看论坛节点信息的api.具体如下: 节点信息 获 ...

  7. pytest.10.使用fixture参数化测试预期结果

    From: http://www.testclass.net/pytest/test_api_with_expected_result/ 背景 接上一节v2ex网站的查看论坛节点信息的api. 我们在 ...

  8. pytest框架 里 fixture 参数化的方法

  9. 【Pytest04】全网最全最新的Pytest框架fixture应用篇(2)

    一.Fixture参数之params参数可实现参数化:(可以为list和tuple,或者字典列表,字典元祖等) 实例如下: import pytest def read_yaml(): '] @pyt ...

随机推荐

  1. php代码审计整理

    目录 变量覆盖 1x01.extract 变量覆盖 定义和用法 语法 漏洞产生:使用了默认设置 攻击方法:制造变量名冲突,对于需要相等的值可以同时置空 修复:设定一个冲突时的处理规则 例题: 1x02 ...

  2. 最新 obs-studio vs2019 开发环境搭建 代码编译

    距离上一篇文章很久了,重新开始记录 OBS 开发相关情况,第一步就是环境搭建,第二步是构建 OBS-Studio VS 2019 开发环境搭建 下载软件和资源 软件安装没有特别说明的,下载安装即可. ...

  3. 浅析Linux 64位系统虚拟地址和物理地址的映射及验证方法

    虚拟内存 先简单介绍一下操作系统中为什么会有虚拟地址和物理地址的区别.因为Linux中有进程的概念,那么每个进程都有自己的独立的地址空间. 现在的操作系统都是64bit的,也就是说如果在用户态的进程中 ...

  4. MySQL高可用(三)搭建主备同步实战

    目标 掌握如何搭建一主一备的主备架构 实验环境 系统:Ubuntu 18.04.1 LTS MySQL版本:5.7.32 主库IP:192.168.200.120 备库IP:192.168.200.1 ...

  5. Java学习_Java快速入门

    Java简介 安装完JDK后,需要设置一个JAVA_HOME的环境变量,它指向JDK的安装目录.在Windows下,它是安装目录,类似: C:\Program Files\Java\jdk-15 把J ...

  6. 在jsp页面嵌入java代码让某些div显示或者隐藏

    <!--监测评价人显示评价人信息 --> <% if("D3".equals(role_flag)){%> <div id="crud&qu ...

  7. JAVA 实体类List<Entity >转 List<Map>

    public static <T extends IdEntity> List<Map<Object,Object>> EntityConvertMap(List& ...

  8. 本地TOMCAT启动打包项目(WAR)

    首先打个包,右击项目-->Export...   选择WEB-->WAR file-->Next   选个放置地址,勾选红框处-->finish   找到自己的tomcat目录 ...

  9. MM-RFQ询价报价

    (1).询价报价单事务码:ME41/ME42/ME43 需要的主数据:采购组织.供应商.采购组,物料 (2)ME47:维护供应商的报价.可以用项目明细的条件对供应商的报价进行详细设置. (3)供应商价 ...

  10. [LeetCode]Subtree of Another Tree判断一棵树是不是另一棵树的子树

    将树序列化为字符串,空节点用符号表示,这样可以唯一的表示一棵树. 用list记录所有子树的序列化,和目标树比较. List<String> list = new ArrayList< ...