UI自动化测试-pytest框架

news2024/11/19 7:28:25

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

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

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

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

安装pytest

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

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

第一个pytest脚本

import pytest

class 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 pytest

class TestDemo:

    @pytest.mark.L1
    @pytest.mark.L2
    def test_01(self):
        assert 1==1  # 断言成功

    @pytest.mark.L2
    def 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 == 1
 
def test_b():
     print('bbbb')
     assert 1 == 2
 
if __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 == 1

    def test_b(self):
        print('bbbb')
        assert 1 == 2


if __name__ == '__main__':
    pytest.main(["-s", "test.py"])

setup和teardown

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

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

import pytest

class TestDemo:
    def setup(self):
        print('setup')
    def teardown(self):
        print('teardown')
    @pytest.mark.L1
    @pytest.mark.L2
    def test_01(self):
        assert 1==1  # 断言成功

    @pytest.mark.L2
    def test_02(self):
        assert 1==2  # 断言失败
if __name__ == '__main__':
    pytest.main(['-s','test.py'])

断言

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

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

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

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

import pytest

class TestDemo:
    
    @pytest.mark.L1
    @pytest.mark.L2
    def test_01(self):
        assert 1==1  # 断言成功
        assert 1==3

    @pytest.mark.L2
    def test_02(self):
        assert 1==2  # 断言失败
if __name__ == '__main__':
    pytest.main(['-s','test.py'])

参数化

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

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

单个参数

import pytest

class TestDemo:
    data = ["小红", "小明"]
    @pytest.mark.parametrize("username",data)
    def test_01(self,username):
        print("我是{}".format(username))


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

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

多个参数

列表嵌套字典

import pytest

class 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 pytest

class 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 pytest

class 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的冰山一角,还有

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

欢迎交流,拜拜!

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

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

相关文章

国产化服务环境中使用gunicorn部署Flask应用并配置开机自启

背景 服务端由第三方部署了一个基于 darknet (一个较为轻型的完全基于C与CUDA的开源深度学习框架)的识别算法服务,通过 Flask 的 Web 服务对业务服务暴露 API 接口。作为测试,一开始是直接通过 python3 app.py 的命令行启动的服务…

Ubuntu安装Anaconda详细步骤

本文主要讲述了在Ubuntu中安装anaconda的具体步骤。 准备环境:Ubuntu,Anaconda3 一、安装Anaconda3 在清华镜像下载Linux版本的anaconda: https://mirrors.bfsu.edu.cn/anaconda/archive/我选择的是Anaconda3-2022.10-Linux-x86_64.sh 下…

数组(7)

目录 1、一维数组 1、数组的创建 2、数组的初始化 3、一维数组的使用 4、一维数组在内存中的存储 2、二维数组 1、二维数组的创建 2、二维数组的初始化 3、二维数组的使用 4、二维数组在内存中的存储 3、数组越界 4、数组作为函数参数 1、冒泡排序: 5…

【学习笔记12.24】关于事务你必须知道的几件事

文章目录事务基础知识什么是事务?开启事务事务隔离级别事务基础知识 在MySQL中,只有InnoDB存储引擎是支持事务的。 什么是事务? 事务是逻辑操作的最小单元,使数据从一个状态转变为另一个状态。 也可以通过事务四大特性ACID来更…

SAP ERP 里的 Costing Sheet 成本核算表

有朋友在我的知识星球里向我提问: 请您帮忙讲一下这个AP0100的costing sheet rows这里都表示什么意思吗?比如row10、base Z010、overhead啥、描述、from、to row、credit都说明了什么,能够实现上面👆🏻的目标吗&#x…

fpga实操训练(vga测试)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 我自己读书那会,买的电脑还是以台式机居多,平板显示器也是才刚刚流行、且价格较高,视频接口也是以VGA为主。不像…

Linux搭建TFTP服务

TFTP是简单文件传输协议,是一个基于UDP协议实现的用在客户及和服务器之间进行简单文件传输的协议,适用于开销不大,不复杂的应用场景。TFTP协议专门为小文件传输而设计,只能从服务器获取文件,或者客户端往服务器写入文件,但是不能进行认证也不能列出目录。 1、安装tftp服…

RV1126笔记十五:吸烟行为检测及部署<三>

若该文为原创文章,转载请注明原文出处。 训练并测试(windows) 一、yolov5安装 1、下载rk优化后的yolov5 git clone https://github.com/airockchip/yolov5.git 下载后,我是放到E:\miniconda3\envs目录下,miniconda3是安装miniconda的目录。可以放到其他地方,后续操作需要…

MySQL提高批量insert的性能

一. 使用批量插入,将多条单独的 insert 合并成一次操作 即:insert into table values (a1, b1, c1), (a2, b2, c2); 解析:将多条 insert 合并后,减少MySQL日志量(即MySQL的 binlog 和 innodb 的事务日志),降低日志刷…

Python pandas有好几百个库函数,你都用过吗(1)

对Python的 pandas 库所有的内置元类、函数、子模块等全部浏览一遍,然后挑选一些重点学习一下。我安装的库版本号为1.3.5,如下: >>> import pandas as pd >>> pd.__version__ 1.3.5 >>> print(pd.__doc__)pandas…

54三数之和55 56有无重复元素的全排列

54 三数之和 首先想到的就是之前的两数之和,只要在外层遍历一遍,对每个元素用之前的两数之和的哈希做法,就刚好是O(n^2) 但是有坑的地方在于需要去重,并且输出的三元组也是需要顺序的!!然后我用set去重和重…

c语言复习之预编译(十四)

1.以#开头的行,都称为编译器指令 #define定义宏#if #else #elif #endif条件编译#ifdef #ifndef判断是否定义了某个宏#error错误#program设定状态或指定完成(编译器)#undef取消宏定义 2.预定义宏 __LINE__行号__FILE__源文件名__DATE__创建…

你以为架构师天天就画图写PPT吗,告诉你其他事儿多了去了~

V-xin:ruyuan0330 获得600页原创精品文章汇总PDF 目录 一、多系统订阅数据回顾二、核心数据的监控系统三、电商库存数据如何监控四、数据计算链路追踪五、百亿流量下的数据链路追踪六、自动化数据链路分析七、下篇预告 上篇文章《为什么我建议线上高并发量的代码&a…

rip综合实验

目录 1.拓扑图 2.要求 3.要求分析 4.主要配置 5.测试 6.实验总结 1.拓扑图 2.要求 R1代表运营商,R1远程登录R2实际登录R9R3访问R7的环回,实际走下面全网可达 3.要求分析 将R2包括右边所有设备理解为一个局域网,在R2的出接口上配置NAT…

BIT.3_Linux进程概念

目录冯诺依曼体系结构操作系统(Operator System)概念设计OS的目的定位如何理解 "管理"总结系统调用和库函数概念进程概念知识点基本概念描述进程-PCBtask_struct-PCB的一种task_ struct内容分类组织进程查看进程通过系统调用获取进程标示符通过系统调用创建进程-fork…

上次面试跪在了Redis上,刷完腾讯云大神亲码的“redis深度笔记”,终面进腾讯!

前言 作为这个时代码代码的秃头人员,对Redis肯定是不陌生的,如果连Redis都没用过,还真不好意思出去面试,指不定被面试官吊打多少次。 毕竟现在互联网公司和一些创业公司都要用到Redis,像亚马逊、谷歌、阿里、腾讯都要使…

使用PicGo+阿里云OSS实现md文档图片上传

使用PicGo阿里云OSS实现md文档图片上传 这次给大家带来的是PicG0阿里云Osstypora的图床环境搭建,帮助大家提高工作效率写博客速度! 1.typora安装 给大家一个链接:typora,打开后点击下载就行,正式版收费,…

Qt扫盲-QTextBrowser理论总结

QTextBrowser理论总结1. 简述2. 文档来源和内容3. 导航4. 用途1. 简述 QTextBrowser 顾名思义其实就是一个文本阅读器,但是这个类类扩展了 QTextEdit 的只读模式功能,当然了 QTextEdit 其实也就是QTextBrowser 的父类。添加的功能主要是一些导航 naviga…

对路由的基本理解和使用

一、认识路由 1、生活中的路由器 构造:路由器上有多个网线接口,每一个接口都对应一台设备 功能:多台设备能同时上网 2、编程中的路由和路由器 (1)后端渲染和后端路由 ①概念 早期的网站开发整个HTML页面是由服务器…

【附源码】如何C语言打印出心形表白?

使用C语言实现打印出心形,初学者的表白神器~ 我们分了4部分,前3行一部分,4-6行一部分,7-13行一部分,最后一行一部分,读者请仔细阅读注释,已经写的很详细了。 前三行输出,为了让初学…