五、UI自动化测试05--PyTest框架

目录

  • [一、PyTest 框架](#一、PyTest 框架)
    • [2. 特点](#2. 特点)
    • [2. 安装步骤](#2. 安装步骤)
    • [3. 基本使⽤](#3. 基本使⽤)
      • [3.1 测试函数形式](#3.1 测试函数形式)
      • [3.2 执⾏⽅式](#3.2 执⾏⽅式)
      • [3.3 测试类形式](#3.3 测试类形式)
      • [3.4 执⾏⽅式](#3.4 执⾏⽅式)
      • [3.5 另⼀种执⾏⽅式: 主函数执⾏](#3.5 另⼀种执⾏⽅式: 主函数执⾏)
      • [3.6 特殊⽅法: 函数级别](#3.6 特殊⽅法: 函数级别)
      • [3.7 特殊⽅法: 类级别](#3.7 特殊⽅法: 类级别)
      • [3.8 特殊⽅法: 函数级别和类级别同时使⽤](#3.8 特殊⽅法: 函数级别和类级别同时使⽤)
    • [4. pytest 配置⽂件](#4. pytest 配置⽂件)
      • [4.1 选项字段获取](#4.1 选项字段获取)
      • [4.2 编写步骤](#4.2 编写步骤)
      • [4.3 使⽤步骤](#4.3 使⽤步骤)
      • [4.4 默认设置](#4.4 默认设置)
      • [4.5 ⾃定义规则](#4.5 ⾃定义规则)
      • [4.6 扩展: 指定单个⽂件/类/⽅法执⾏](#4.6 扩展: 指定单个⽂件/类/⽅法执⾏)
  • [二、 pytest 常⽤插件](#二、 pytest 常⽤插件)
    • [1. HTML 报告插件](#1. HTML 报告插件)
      • [1.1 安装步骤](#1.1 安装步骤)
      • [1.2 使⽤步骤](#1.2 使⽤步骤)
    • [2. 控制⽅法执⾏顺序插件](#2. 控制⽅法执⾏顺序插件)
      • [2.1 安装步骤](#2.1 安装步骤)
      • [2.2 使⽤步骤](#2.2 使⽤步骤)
    • [3. 失败重试插件](#3. 失败重试插件)
      • [3.1 安装步骤](#3.1 安装步骤)
      • [3.2 使⽤步骤](#3.2 使⽤步骤)
  • [三、pytest ⾼级功能](#三、pytest ⾼级功能)
    • [1. 跳过操作](#1. 跳过操作)
    • [2. 参数化操作](#2. 参数化操作)
      • [2.1 单个参数](#2.1 单个参数)
      • [2.2 多个参数](#2.2 多个参数)
    • [3. 扩展: 断⾔⽅法的使⽤](#3. 扩展: 断⾔⽅法的使⽤)
      • [3.1 Python ⾃带的断⾔⽅法](#3.1 Python ⾃带的断⾔⽅法)
      • [3.2 pytest 框架中使⽤断⾔](#3.2 pytest 框架中使⽤断⾔)
  • [四、PO 设计模式](#四、PO 设计模式)
    • [1. v0 版本](#1. v0 版本)
    • [2. 账户不存在脚本](#2. 账户不存在脚本)
    • [3. 密码错误脚本](#3. 密码错误脚本)

一、PyTest 框架

  • 说明: pytest 是 Python 的⼀种单元测试框架,同⾃带的 UnitTest 测试框架类似,相⽐ UnitTest 框架使⽤起来更简洁,效率更⾼。(在⾃动化测试中同样充当测试执⾏的功能! 并且可以跟 UnitTest 互换)

2. 特点

    1. ⾮常容易上⼿,⼊⻔简单,⽂档丰富,⽂档中有很多实例可以参考
  • 官⽅⽂档地址: https://docs.pytest.org/en/6.2.x/
    1. ⽀持简单的单元测试和复杂的功能测试
    1. ⽀持参数化: UnitTest 需要通过插件扩展参数化功能!
    1. 执⾏测试过程中可以将某些测试跳过,或者对某些预期失败的 Case 标记成失败
    1. ⽀持重复执⾏失败的 Case : 通过安装插件实现
    1. ⽀持运⾏由 Nose,UnitTest 编写的测试 Case : pytest 框架的脚本在 UnitTest 下⽆法执⾏
    1. 具有很多第三⽅插件,并且可以⾃定义扩展
  • 插件获取⽹站:
    1. ⽅便的和持续集成⼯具集成

2. 安装步骤

说明: 与 UnitTest 不同的是, pytest 框架需要先安装才能使⽤!

安装与查看版本步骤

3. 基本使⽤

3.1 测试函数形式

python 复制代码
# 函数形式
def test_func(): # 要求函数名以 test 开头
 """测试函数"""
 print('我是测试函数')

3.2 执⾏⽅式

3.3 测试类形式

python 复制代码
# 测试类形式
class TestDemo(object): # 正常定义类, 但是测试类名必须以 Test 开头
 """测试示例类"""
 
 def test_method1(self): # 正常定义⽅法, 但是测试⽅法名必须以 
test 开头
 """测试⽅法1"""
 print('测试⽅法1')
 
 def test_method2(self):
 """测试⽅法2"""
 print('测试⽅法2')

3.4 执⾏⽅式

3.5 另⼀种执⾏⽅式: 主函数执⾏

说明: 使⽤主函数, 可以实现在代码⽂件内, ⿏标右键菜单执⾏

  • 测试函数形式下使⽤
python 复制代码
# 测试函数形式
import pytest
 
 
def test_func(): # 要求函数名以 test 开头
 """测试函数"""
 print('我是测试函数')
 
 
if __name__ == '__main__':
 # 语法: pytest.main(['-s', '⽂件名.py'])
 pytest.main(['-s', 'hm03_pytest_basic_03.py'])
  • 测试类形式下使⽤
python 复制代码
# 测试类形式
import pytest
 
 
class TestDemo(object): # 正常定义类, 但是测试类名必须以 Test 开头
 """测试示例类"""
 
 def test_method1(self): # 正常定义⽅法, 但是测试⽅法名必须以 test 开头
 """测试⽅法1"""
 print('测试⽅法1')
 
 def test_method2(self):
 """测试⽅法2"""
 print('测试⽅法2')
 
 
if __name__ == '__main__':
 # 语法: pytest.main(['-s', '⽂件名.py'])
 pytest.main(['-s', 'hm04_pytest_basic_04.py'])

3.6 特殊⽅法: 函数级别

  • 说明: 函数级别特殊⽅法的执⾏逻辑与 UnitTest 中的 Fixture 的⽅法级别的执⾏逻辑⼀致!
python 复制代码
"""
特殊⽅法: 函数级别
"""
import pytest
 
 
class TestDemo(object):
 """测试示例类"""
 
 # 说明: 特殊⽅法名写法固定, 没有代码提示, 需要⼿写!
 # 注意: 函数级别执⾏顺序: 
 # 先 setup() -> 测试⽅法1 -> teardown() ⽅法, 再 setup() -> 测试⽅法2 -> teardown() ⽅法
	def setup(self):
 		"""开始⽅法"""
		 print('函数 -> 开始')
 
 	def teardown(self):
		 """结束⽅法"""
 		print('函数 -> 结束')
 
	def test_method1(self):
		 """示例测试⽅法"""
		 print('测试⽅法1')
 
	def test_method2(self):
		 """示例测试⽅法"""
		 print('测试⽅法2')
 
 
if __name__ == '__main__':
 	pytest.main(['-s', 'hm05_pytest_basic_05.py'])

3.7 特殊⽅法: 类级别

  • 说明: 类级别特殊⽅法的执⾏逻辑与 UnitTest 中的 Fixture 的类级别的执⾏逻辑⼀致!
python 复制代码
"""
特殊⽅法: 类级别
"""
import pytest
class TestDemo(object):
 """测试示例类"""
 
 # 说明: 特殊⽅法名写法固定, 没有代码提示, 需要⼿写!
 # 注意: 类级别执⾏顺序:
 # 先 setup_class() -> 测试⽅法1 -> 测试⽅法2 -> 
teardown_class() ⽅法
 
 def setup_class(self):
 """开始⽅法"""
 print('类 -> 开始')
 
 def teardown_class(self):
 """结束⽅法"""
 print('类 -> 结束')
 
 def test_method1(self):
 """示例测试⽅法"""
 print('测试⽅法1')
 
 def test_method2(self):
 """示例测试⽅法"""
 print('测试⽅法2')
 
 
if __name__ == '__main__':
 pytest.main(['-s', 'hm06_pytest_basic_06.py'])

3.8 特殊⽅法: 函数级别和类级别同时使⽤

python 复制代码
"""
特殊⽅法: 函数级别和类级别同时使⽤
"""
import pytest
 
 
class TestDemo(object):
 """示例测试类"""
 
 # 执⾏顺序: 1 -> 3 -> 5 -> 4 -> 3-> 6 -> 4 -> 2
 
 def setup_class(self): # 1
 print('类级别 ->> 开始')
 
 def teardown_class(self): # 2
 print('类级别 ->> 结束')
 
 def setup(self): # 3
 print('函数级别 -> 开始')
 
 def teardown(self): # 4
 print('函数级别 -> 结束')
 
 def test_method1(self): # 5
 """测试⽅法1"""
 print('测试⽅法1')
 
 def test_method2(self): # 6
 """测试⽅法2"""
 print('测试⽅法2')

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

4. pytest 配置⽂件

  • 说明: 使⽤配置⽂件后可以快速的使⽤配置的项来选择执⾏哪些测试模块
  • 注意:
    *
    1. 在 Windows 系统下, pytest 配置⽂件中, 不允许写注释信息
      1. ⼀个⼯程内只需要⼀个 pytest 配置⽂件, 并且需要保证⽂件名正确
      1. ⼀般情况, 只需要将 pytest 配置⽂件, 置于⼯程根⽬录下
      1. 配置有 pytest 配置⽂件的⼯程, 只需要打开命令⾏, 输⼊ pytest 指令, 即可执⾏测试

4.1 选项字段获取

4.2 编写步骤

4.3 使⽤步骤

  • 说明: 打开命令⾏ -> 输⼊ pytest -> 执⾏即可

4.4 默认设置

  • 说明: 测试⽤例⽂件名/测试类名/测试⽅法名均为 Test/test 开头

pytest

testpaths = ./case

addopts = -s

python_files = test*.py

python_classes = Test*

python_functions = test*

4.5 ⾃定义规则

  • 说明: 测试⽤例⽂件名/测试类名/测试⽅法名, 需要根据具体项⽬进⾏设置, 以下以 Hm/hm为例

pytest

testpaths = ./case

addopts = -s

python_files = hm*.py

python_classes = Hm*

python_functions = hm*

4.6 扩展: 指定单个⽂件/类/⽅法执⾏

pytest

testpaths = ./case

addopts = -s

python_files = demo_case1.py

python_classes = DemoDemo1

python_functions = demo_method1

二、 pytest 常⽤插件

1. HTML 报告插件

1.1 安装步骤

  • ⽅式1 -> 安装: pip install pytest-html
  • ⽅式2 -> PyCharm 中安装

1.2 使⽤步骤

    1. 在 pytest 配置⽂件中, 增加命令选项
    • 选项: --html=./报告路径/报告⽂件名.html --self-contained-html
    • 说明: --self-contained-html 将 CSS ⽂件内嵌到报告⽂件中
    1. 执⾏ pytest 指令, 运⾏测试即可
  • 添加命令选项执⾏

  • 查看⽣成的报告内容

2. 控制⽅法执⾏顺序插件

2.1 安装步骤

  • ⽅式1 -> 安装: pip install pytest-ordering
  • ⽅式2 -> PyCharm 中安装

2.2 使⽤步骤

  • 说明: 直接在测试类或测试⽅法上⽅添加 @pytest.mark.run(order=序号)
python 复制代码
"""
pytest 控制⽅法执⾏顺序插件
"""
import pytest

@pytest.mark.run(order=2)
class TestDemo(object):
 """示例测试类"""
 
 # 语法: @pytest.mark.run(order=序号)
 # 注意: run(order=序号) 没有代码提示, 需要⼿写!
 
 # @pytest.mark.run(order=-3)
 def test_method1(self):
 """测试⽅法1"""
 print('测试⽅法1')
 
 # @pytest.mark.run(order=1)
 def test_method2(self):
 """测试⽅法2"""
 print('测试⽅法2')
 
 # @pytest.mark.run(order=2)
 def test_method3(self):
 """测试⽅法3"""
 print('测试⽅法3')
 
 # 扩展: 序号⽀持正数和负数, 以及正负混合
 # 1. 纯正数: 数越⼩, 优先级越⾼[掌握]
 # 2. 纯负数: 数越⼩, 优先级越⾼[了解]
 # 3. 正负混合: 正数先按照顺序执⾏, 负数最后执⾏[了解]
 
 
# 注意: 控制⽅法执⾏顺序对测试类同样有效!
@pytest.mark.run(order=1)
class TestDemo2(object):
 """测试类2"""
  def test_method(self):
	 print('测试类2 -> 测试⽅法')
 

3. 失败重试插件

3.1 安装步骤

  • ⽅式1 -> 安装: pip install pytest-rerunfailures
  • ⽅式2 -> PyCharm 中安装

3.2 使⽤步骤

    1. 在 pytest 配置⽂件中, 增加命令选项
    • 选项: --reruns 次数
    1. 执⾏ pytest 指令, 运⾏测试即可

三、pytest ⾼级功能

1. 跳过操作

  • 说明: 对于完成的代码或版本不对应的代码, 可以设置跳过使之不参与测试执⾏
python 复制代码
"""
跳过功能
"""
import pytest

version = 25 # 模拟软件版本号变量
 
 
class TestDemo1(object):
 """示例测试类"""
 
 def test_method1(self):
 """测试⽅法"""
 print('测试⽅法1')
 
 # 语法: @pytest.mark.skipif(符合的条件, reason='跳过的原因')
 # 说明: 如果满⾜条件, 以下⽅法或测试类执⾏跳过, 不执⾏!
 # 注意: reason= 不能省略, 否则报错!
 # @pytest.mark.skipif(version >= 25, 'xxx') # 错误样例
 @pytest.mark.skipif(version >= 25, reason='当前版本不执⾏') # 
正确样例
 def test_method2(self):
 """测试⽅法"""
 print('测试⽅法2')
 
 
# 说明: 同样可以跳过测试类
@pytest.mark.skipif(version >= 25, reason='当前版本不执⾏')
class TestDemo2(object):
 """示例测试类2"""
 
 def test_method(self):
 print('测试类2 -> 测试⽅法')
 
 
if __name__ == '__main__':
 pytest.main(['-s', 'hm10_pytest_skip.py'])

2. 参数化操作

  • 说明: 与 UnitTest 框架不同, pytest 框架⾃带参数化功能, 调⽤对应⽅法并传⼊数据, 即可完成参数化实现

2.1 单个参数

python 复制代码
"""
pytest 参数化功能: 单个参数
"""
import pytest
 
 
class TestDemo(object):
 """示例测试类"""
 
 # 语法: @pytest.mark.parametrize('参数变量', ['数值1', '数值
2', ...])
 @pytest.mark.parametrize('name', ['⼩明', '⼩刚', '⼩红'])
 def test_method(self, name):
 """测试⽅法"""
 print('获取的名字是:', name)
 
 
if __name__ == '__main__':
 pytest.main(['-s', 'hm11_pytest_para1.py'])

2.2 多个参数

python 复制代码
"""
pytest 参数化: 多个参数
"""
import pytest
 
 
class TestDemo(object):
 """示例测试类"""
 
 # 语法: @pytest.mark.parametrize('参数1, 参数n', [(数据1-1, 数
据1-2), (数据2-1, 数据2-2), ...])
 # 注意:
 # 1. 多个参数必须置于同⼀个字符串内!
 # 2. 数据格式必须是: [(), ()] 或者 [[], []]
 # 扩展: 另⼀种写法
 # @pytest.mark.parametrize(('name', 'pwd'), [('admin', 
123456), ('test', 654321), ('xxx', 'yyy')])
 @pytest.mark.parametrize('name, pwd', [('admin', 123456), 
('test', 654321), ('xxx', 'yyy')])
 def test_method(self, name, pwd):
 """测试⽅法"""
 print('账号:{} 密码:{}'.format(name, pwd))
 
 
if __name__ == '__main__':
 pytest.main(['-s', 'hm12_pytest_para2.py'])

3. 扩展: 断⾔⽅法的使⽤

  • 说明: 与 UnitTest 框架不同的是, pytest 框架使⽤ Python ⾃带的断⾔⽅法实现断⾔操作的

3.1 Python ⾃带的断⾔⽅法

python 复制代码
# 语法: assert 表达式
# 说明: 断⾔后接的表达式的结果为 Ture(断⾔通过), 为 False(断⾔失败)
# 预期相等:
assert 1 == 1
# 预期包含:
assert 'admin' in '欢迎 admin 归来!'

3.2 pytest 框架中使⽤断⾔

python 复制代码
"""
pytest 断⾔
"""
import pytest
 
 
def add_func(num1, num2):
 """加法函数"""
 return num1 + num2
 
 
class TestDemo(object):
 """示例测试类"""
 
 	def test_method(self):
 		"""加法测试⽅法"""
 		 # 调⽤被测函数
 		result = add_func(1, 2)
		 # 断⾔判断结果
		 assert 4 == result
 
 
if __name__ == '__main__':
	 pytest.main(['-s', 'hm14_pytest_assert.py'])

四、PO 设计模式

1. v0 版本

  • 特点: 对于同⼀个待测模块, 对应的测试代码步骤完全⼀致, 只有测试数据存在差异, 因此对于反复出现的相同逻辑的测试代码, 需要考虑通过封装的思路对⻬进⾏整理, 以提⾼测试脚本的编写效率.
  • 注意: 通过直接定位元素并操作元素的⽅式实现的⾃动化脚本, 已经算是 UI ⾃动化的实现形式了!

2. 账户不存在脚本

python 复制代码
"""
账号不存在测试⽤例
"""
from time import sleep
from selenium import webdriver
 
driver = webdriver.Chrome()
driver.get('http://127.0.0.1/')
driver.maximize_window() # 窗⼝最⼤化
driver.implicitly_wait(10) # 隐式等待
 
# 1. 点击⾸⻚的'登录'链接,进⼊登录⻚⾯
driver.find_element_by_link_text('登录').click()
 
# 2. 输⼊⼀个不存在的⽤户名
driver.find_element_by_id('username').send_keys('13811110001')
# 3. 输⼊密码
driver.find_element_by_id('password').send_keys('123456')
# 4. 输⼊验证码
driver.find_element_by_id('verify_code').send_keys('8888')
# 5. 点击登录按钮
driver.find_element_by_name('sbtbutton').click()
 
# 6. 获取错误提示信息
# 获取元素⽂本值: 元素对象.text
msg = driver.find_element_by_class_name('layui-layercontent').text
print('错误信息为:',
msg)
 
sleep(3)
driver.quit()

3. 密码错误脚本

python 复制代码
"""
密码错误测试⽤例
"""
from time import sleep
from selenium import webdriver

driver = webdriver.Chrome()
driver.get('http://127.0.0.1/')
driver.maximize_window() # 窗⼝最⼤化
driver.implicitly_wait(10) # 隐式等待
 
# 1. 点击⾸⻚的'登录'链接,进⼊登录⻚⾯
driver.find_element_by_link_text('登录').click()
 
# 2. 输⼊⽤户名
driver.find_element_by_id('username').send_keys('13800001111')
# 3. 输⼊错误密码
driver.find_element_by_id('password').send_keys('error')
# 4. 输⼊验证码
driver.find_element_by_id('verify_code').send_keys('8888')
# 5. 点击登录按钮
driver.find_element_by_name('sbtbutton').click()
 
# 6. 获取错误提示信息
# 获取元素⽂本值: 元素对象.text
msg = driver.find_element_by_class_name('layui-layercontent').text
print('错误信息为:',
msg)
 
sleep(3)
driver.quit()
相关推荐
keep intensify16 分钟前
数据结构---单链表的增删查改
c语言·数据结构·c++·经验分享·学习·算法·分享
刘立军1 小时前
本地大模型编程实战(26)用langgraph实现基于SQL数据构建的问答系统(5)
人工智能·后端·python
初心_20241 小时前
2. python协程/异步编程详解
java·前端·python
Psycho_MrZhang1 小时前
Pytorch 反向传播
人工智能·pytorch·python
TeleostNaCl2 小时前
CMCC RAX3000M使用Tftpd刷写OpenWrt固件的救砖方法
经验分享·智能路由器
这里有鱼汤2 小时前
别怪 Python 慢,是你 import 的姿势不对!我亲测提速 3~5 倍
后端·python
hyhrosewind2 小时前
Python数据容器:数据容器的分类、数据容器特点总结、各数据容器遍历的特点、数据容器通用操作(统计,转换,排序)
python·数据容器的分类·各数据容器的特点·各数据容器的遍历·数据容器的通用操作·统计,转换,排序
灏瀚星空2 小时前
从基础到实战的量化交易全流程学习:1.3 数学与统计学基础——线性代数与矩阵运算 | 矩阵基础
笔记·python·学习·线性代数·数学建模·金融·矩阵
Amctwd2 小时前
【LLM】解析RAG增强检索技术:原理、实现与应用
python