UI自动化测试-pytest框架

 🔥 交流讨论:欢迎加入我们一起学习!

🔥 资源分享耗时200+小时精选的「软件测试」资料包

🔥 教程推荐:火遍全网的《软件测试》教程  

📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!

在进行UI自动化测试的时候,我们需要工具来对测试用例进行收集,执行,标记,参数化。pytest就是这样一个工具。

pytest实际是python的一个单元测试框架,其他还有如unittest等,它可以实现按照规则搜索测试用例,对测试用例进行标记,如只执行L1

级别的测试用例,测试执行用例失败后重新执行,测试用例的参数化等。

pytest不仅适用于UI自动化测试,也适用于接口自动化,对python语言进行单元测试等。

安装pytest

可以使用pip或者pycharm方式进行安装

打开pycharm,左上角File-settings-project:项目名-python interpreter,点击+,搜索pytest,然后install package

第一个pytest脚本

import pytestclass TestDemo:def test_01(self):assert 1==1  # 断言成功def test_02(self):assert 1==2  # 断言失败
if __name__ == '__main__':pytest.main(['-s','test.py'])

在文件输入如上代码。

在这个脚本中,我们首先导入了pytest模块,然后定义了一个class,并定义了两个方法,在方法里用assert进行断言。

assert是python自带的关键字。assert后面接一个表达式,只要表达式的最终结果为True,那么断言通过,用例执行成功,否则用例执行失败。可以看出,第一个方法里结果为true,第二个方法里结果为false。

在main主入口里,调用pytest的main方法,并传入模块名(即文件名)。

点击运行按钮,结果如下:

由结果可以看出,一共收集了两个用例,其中一个运行成功(用.表示),一个运行失败(F表示),失败的原因是1!=2

用例收集规则

pytest按照一定的规则进行用例的收集。

1. 模块名必须以test_开头或_test结尾

这里适用于未指定模块时的收集,如果运行单个文件,在main里指定要执行的文件,则无论这个文件名是什么,都会被执行。

如果在main里不指定模块,如只写pytest.main(),则pytest会默认从当前路径及其所有子目录中搜索py源文件,所有名字以test_开头或者以_test结尾的python源文件(.py文件)被认为是测试模块源文件,不符合这个命名规则的文件会被忽略。

2. 测试类必须以Test开头且不能有init方法

一个文件也可以只写测试方法,不写测试类。

3. 测试方法必须以test开头

在上面的示例脚本中,我们定义了两个test_开头的方法,所以收集了两个用例。非test开头的方法,会被pytest忽略。

运行方式

main函数运行

我们可以在main入口中调用pytest的main方法来运行文件,如上例。

不指定模块名
pytest.main(['-s'])

-s参数表示在控制台输出信息,当不指定模块名时,可以看到,收集了7条用例

指定模块名
 pytest.main(['-s','test.py'])

当指定了模块后,运行文件,只收集当前文件的两条用例。

指定class
 pytest.main(["-s", "test.py::TestDemo"])

我们也可以在模块名上加上指定的class名

命令行窗口运行

不指定模块名

打开terminal,进入目标目录,直接执行“pytest”即可自动寻找当前目录下的测试用例

指定模块名

打开terminal,输入pytest+模块名,指定模块执行。

pytest test.py

指定函数名

打开terminal,输入pytest+模块名+函数名,指定模块执行。

pytest test.py::TestDemo

test runner运行

在File-Settings如图路径,设置default test runner为pytest,点击OK。

再回到测试文件,可以看到类,方法前面都显示运行按钮,点击对应按钮,可以运行类,单独运行某个test。

也可以在不写main函数的情况下,右键以pytest运行文件。注意在配置了runner后,执行不会进入main主入口。

标记机制

pytest提供了标记机制,借助“mark”关键字,我们可以对测试函数(类、方法)进行标记。

我们可以利用标记,对测试用例进行分级,例如某些主流程的用例可以标记为L1,次要流程的用例标记为L2等。这样有一个好处,我们可以在不同的情况执行不同的测试用例,例如,在做冒烟测试的时候,只需要执行L1级别的用例就行了。

●一个测试函数(类、方法)可以有多个标记。

●一个标记也可以应用于多个函数(类、方法)。

●执行参数使用:pytest -m mark名。

●执行多个标记:pytest -m “L1 or L2”。

import pytestclass TestDemo:@pytest.mark.L1@pytest.mark.L2def test_01(self):assert 1==1  # 断言成功@pytest.mark.L2def test_02(self):assert 1==2  # 断言失败
if __name__ == '__main__':pytest.main(['-m L2','test.py'])

如上,给测试用例添加标记,并在main中以-m参数指定选择的标记,也可以使用or和and。

  pytest.main(['-m L2 or L1','test.py']) # 执行标记为L1或者L2的
  pytest.main(['-m L2 and L1','test.py']) #执行标记同时为L1和L2的

测试固件

在进行UI测试时,可能每个用例的操作前提都是需要登录系统,那么我们也不能在每次写用例的时候,都把登录写一遍,或者调用一遍,这样会造成代码冗余。有没有可能,在整个测试类或者所有测试用例执行之前,调用一次登录呢?

这样的工具,就是测试固件,测试固件有不同级别。

函数中的测试固件

●setup_module、teardown_module,在整个文件的开始和最后执行一次。

●setup_function和teardown_function,在每个函数开始前后执行。


import pytest'''
在函数中使用
1.setup_module、teardown_module,在整个文件的开始和最后执行一次
2.setup_function和teardown_function,在每个函数开始前后执行
'''
def setup_module():print('setup_module')def teardown_module():print('teardown_module')def setup_function():print('setup_function')def teardown_function():print('teardown_function')def test_a():print('aaaa')assert 1 == 1def test_b():print('bbbb')assert 1 == 2if __name__ == '__main__':pytest.main(["-s", "test.py"])

class中的测试固件

●setup_class、teardown_class,在整个class的开始和最后执行一次。

●setup_method和teardown_method,在每个方法开始前后执行。

class TestDemo():def setup_class(self):print('setup_class')def teardown_class(self):print('teardown_class')def setup_method(self):print('setup_method')def teardown_method(self):print('teardown_method')def test_a(self):print('aaaa')assert 1 == 1def test_b(self):print('bbbb')assert 1 == 2if __name__ == '__main__':pytest.main(["-s", "test.py"])

setup和teardown

setup和teardown既可以应用在函数中,也可以应用在class中,作用对象是函数或方法,在每个测试用例执行前后执行一次。

我们通常使用setup来进行一些数据准备工作,使用teardown来进行数据清理工作。

import pytestclass TestDemo:def setup(self):print('setup')def teardown(self):print('teardown')@pytest.mark.L1@pytest.mark.L2def test_01(self):assert 1==1  # 断言成功@pytest.mark.L2def test_02(self):assert 1==2  # 断言失败
if __name__ == '__main__':pytest.main(['-s','test.py'])

断言

我们在进行手工测试时,测试用例有预期结果,那么在进行UI测试时,我们也需要来判定结果是否符合我们的预期。

在python中用断言来实现。断言assert用于检查指定的表达式的结果是否为True。

一个测试用例可以写多个断言,当有一个断言失败时,pytest就认为测试的结果为失败,该测试用例的执行会被终止。

如果一条测试用例不写断言,那么它的结果为通过。所以一定要写断言,否则测试执行就没有了意义。

import pytestclass TestDemo:@pytest.mark.L1@pytest.mark.L2def test_01(self):assert 1==1  # 断言成功assert 1==3@pytest.mark.L2def test_02(self):assert 1==2  # 断言失败
if __name__ == '__main__':pytest.main(['-s','test.py'])

参数化

在进行UI测试时,我们需要给测试用例传测试数据,那么如何做呢?

pytest使用@pytest.mark.parametrize装饰器来实现数据驱动测试,也就是常说的参数化。

单个参数

import pytestclass TestDemo:data = ["小红", "小明"]@pytest.mark.parametrize("username",data)def test_01(self,username):print("我是{}".format(username))if __name__ == '__main__':pytest.main(['-s','test.py'])

运行结果如下,这里给一条测试用例传入两条数据,显示收集到了两条用例。

多个参数

列表嵌套字典
import pytestclass TestDemo:data_1 = [{"username": "admin1", "password": "123456"},{"username": "admin2", "password": "12345678"},]@pytest.mark.parametrize("data", data_1)def test_login(self,data):print("账号:{},密码:{}".format(data["username"], data["password"]))if __name__ == '__main__':pytest.main(['-s','test.py'])

可以看到这里传入两条数据,显示收集了两条用例。

列表嵌套列表
import pytestclass TestDemo:data_1 = [["admin1", "123456"],["admin2", "12345678"],]@pytest.mark.parametrize("username,password", data_1)def test_login(self,username, password):print("账号:{},密码:{}".format(username, password))if __name__ == '__main__':pytest.main(['-s','test.py'])

列表嵌套元组
import pytestclass TestDemo:data_1 = [("admin1", "123456"),("admin2", "12345678"),]@pytest.mark.parametrize("username,password", data_1)def test_login(self,username, password):print("账号:{},密码:{}".format(username, password))if __name__ == '__main__':pytest.main(['-s','test.py'])

本文介绍了pytest测试框架的安装、运行、用例收集、标记、测试固件、断言、参数化等内容,实际这些内容只是pytest的冰山一角,还有

失败重跑,测试报告,全局设置等内容没有进行介绍,但学习了本文的内容,相信你已经可以上手进行自动化测试用例的编写了。

欢迎交流,拜拜!

最后我邀请你进入我们的【软件测试学习交流群:785128166】, 大家可以一起探讨交流软件测试,共同学习软件测试技术、面试等软件测试方方面面,还会有免费直播课,收获更多测试技巧,我们一起进阶Python自动化测试/测试开发,走向高薪之路

作为一个软件测试的过来人,我想尽自己最大的努力,帮助每一个伙伴都能顺利找到工作。所以我整理了下面这份资源,现在免费分享给大家,有需要的小伙伴可以关注【公众号:程序员二黑】自提!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/803180.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Lua热更新(AssetBundle)

AssetBundle 新版本导入ab包报错,则删除其中的Tests文件夹。 给资源分组 打包设置:平台、路径、重复打包清空文件夹、复制到streaming文件夹 建议勾选 建议使用LZ4压缩方式 用来观察文件中的包大小,不常用 参数总结: 这六个只做了解,重要的是上面的

深入解析Cookie、Session以及Token原理

一、概述 1.1 HTTP无状态问题 目前主流的服务采用的是B\S架构,即浏览器\服务端架构。一般采用的协议是HTTP,HTTP有个特点是无状态,即在一次连接,两次成功请求之间没有任何的关系。这个特性既带来了一定的优点,在某些…

Struts2的入门:新建项目——》导入jar包——》jsp,action,struts.xml,web.xml——》在项目运行

文章目录 配置环境tomcat 新建项目导入jar包新建jsp界面新建action类新建struts.xml,用来配置action文件配置Struts2的核心过滤器:web.xml 启动测试给一个返回界面在struts.xml中配置以实现页面的跳转:result再写个success.jsp最后在项目运行 配置环境 …

【数据分享】我国第七次人口普查的100m分辨率人口栅格数据(免费获取\tif格式\2020年)

人口空间分布数据是我们在各项研究中经常使用的数据。之前我们分享过来源于LandScan数据集的2000-2022年的1km精度的人口空间分布栅格数据(可查看之前的文章获悉详情)! 相较于LandScan全球人口数据集,我国历次人口普查的数据对于…

SpringBoot通用模块--文件上传开发(阿里云OSS)

文件上传,是指将本地图片、视频、音频等文件上传到服务器上,可以供其他用户浏览或下载的过程。文件上传在项目中应用非常广泛,我们经常发抖音、发朋友圈都用到了文件上传功能。 实现文件上传服务,需要有存储的支持,那…

基于支持 GPT 的服务的初创公司

Kafkai:多语言长篇内容生成,AI写作的新趋势 介绍 随着生成式预训练 Transformer (GPT) 的出现,技术世界正在见证范式转变。 这种人工智能驱动的创新不仅仅是一种转瞬即逝的趋势,而是一种趋势。 它已成为科技行业的基石&#xff0c…

部分国企笔试总结

2024.3.30相城区某国企笔试 客观题,30分 类似考公行测题(大部分)部分计算机专业基础知识(仅几题) 主观题,70分 网络安全类一道C编程题:用户输入圆半径r,程序计算面积和周长并输出…

【C语言】简单介绍进制和操作符

🌈个人主页:是店小二呀 🌈C语言笔记专栏:C语言笔记 🌈C笔记专栏: C笔记 🌈喜欢的诗句:无人扶我青云志 我自踏雪至山巅 本文简要介绍进制和操作符,愿能为您提供帮助!文章…

异常的种类

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 Oracle 运行时错误可以分为 Oracle 错误和用户自定义错误,与此对应,根据异常产生的机制和原理,可将 Oracle 的系统异常分为 3 种 预定义…

【Linux】libgpiod使用方法

1、libgpiod库的移植 参见本人博客:libgpiod库的移植 2、libgpiod使用 2.1 打开GPIO芯片 一个GPIO芯片管理N个GPIO,每个GPIO芯片用结构体 ==gpiod_chip == 来表示。 1)以路径方式打开 例如GPIO芯片的路径为:/dev/gpiochip0 struct gpiod_chip *gpiod_chip_open(const …

使用VPN时,Java程序无法访问远程网络的解决办法

应用场景: 电脑连接VPN之后,Java程序无法连接远程服务,比如第三方接口、远程数据库连接、远程微服务等。我个人遇到的情况有连接海康威视SDK,influxdb以及一些微服务。 解决办法: 启动Java时加入参数:-D…

一个嵌入式ucosII系统的典型代码范例

在嵌入式系统开发中,uC/OS-II是一个非常流行的实时操作系统。它提供了许多功能,包括任务管理、信号量、消息邮箱、事件标志等,使得开发者能够更轻松地实现复杂的系统功能。在本文中,我们将展示一个完整的uC/OS-II示例代码&#xf…

41.Python从入门到精通—格式化日期 获取某月日历 Time 模块 日历(Calendar)模块 其他相关模块和函数

41.Python从入门到精通—格式化日期 获取某月日历 Time 模块 日历(Calendar)模块 其他相关模块和函数 格式化日期获取某月日历Time 模块日历(Calendar)模块其他相关模块和函数 格式化日期 在 Python 中,可以使用 strf…

比较好玩的车子 高尔夫6

https://www.sohu.com/a/484063087_221273 四万多如愿收获手动挡高尔夫6,可靠性、经济性、操控性兼顾_搜狐汽车_搜狐网 2.基本上其他人也不知道到底是什么相关的车子信息

基于单片机和ICL7135多档位数字电压表设计

**单片机设计介绍,基于单片机和ICL7135多档位数字电压表设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机和ICL7135的多档位数字电压表设计是一个结合了硬件与软件技术的综合性项目。这种设计旨在实现一…

四种锁(互斥锁,递归锁,读写锁,自旋锁)

1.互斥锁(mutex):互斥锁是最常见的一种锁,用来保护共享资源的互斥访问。一次只有一个线程可以获得互斥锁。如果其他线程试图获得已经被锁定的互斥锁,他们将被阻塞,直到锁被释放 2.递归锁(recursive lock):递归锁是一种特殊的互斥锁,允许同一个线程多次获得同一个锁,而不会导致死…

[lesson12]经典问题解析一

经典问题解析一 关于const的疑问 const常量的判别准则 只有用字面量初始化的const常量才会进入符号表使用其他变量初始化的const常量仍然是只读变量被volatile修饰的const常量不会进入符号表 在编译期间不能直接确定初始值的const标识符,都被作为只读变量处理 con…

Pnpm + Turbo 搭建 Web Component Monorepo 组件库

技术选型 使用 Pnpm Turbo 搭建 Web Component Monorepo项目 stencil-component-ui 组件库 pnpm 作为包管理器Turborepo 作为构建系统Vitepress 管理文档 pnpm 技术 什么是 pnpm? 它有哪些优势? pnpm 跟 npm、yarn一样,都是用于管理Node包依赖的管…

iOS App Store审核要求与Flutter应用的兼容性分析

本文探讨了使用Flutter开发的iOS应用能否上架,以及上架的具体流程。苹果提供了App Store作为正式上架渠道,同时也有TestFlight供开发者进行内测。合规并通过审核后,Flutter应用可以顺利上架。但上架过程可能存在一些挑战,因此可能…

云岚到家项目

一.项目介绍 云岚到家项目是一个家政服务o2o平台,互联网家政是继打车、外卖后的又一个风口,创业者众多,比如:58到家,天鹅到家等,o2o(Online To Offline)是将线下商务的机会与互联网…