pytest学习

pytest学习

文章目录

  • pytest学习
    • [1. 用例结果](#1. 用例结果)
    • [2. 用例发现规则](#2. 用例发现规则)
    • [3. 用例内容规则](#3. 用例内容规则)
    • [4. 小测试](#4. 小测试)
    • [5. 配置框架](#5. 配置框架)
    • [6. 标记mark](#6. 标记mark)
      • [1. 用户自定义标记](#1. 用户自定义标记)
      • [2. 框架内置标记](#2. 框架内置标记)
    • [7. 数据驱动测试参数](#7. 数据驱动测试参数)
    • [8. 夹具fixture](#8. 夹具fixture)
      • [1. 创建使用fixture](#1. 创建使用fixture)
      • [2. 高级用法](#2. 高级用法)
    • [9. 插件](#9. 插件)
      • [1. 插件管理](#1. 插件管理)
      • [2. 常用第三方插件](#2. 常用第三方插件)
    • [10. 企业级测试报告](#10. 企业级测试报告)
    • [11. Web自动化测试](#11. Web自动化测试)
    • [12. 测试框架要封装什么](#12. 测试框架要封装什么)
    • [13. YAML文件格式](#13. YAML文件格式)
      • [13.1 安装yaml文件](#13.1 安装yaml文件)
      • [13.2 编写yaml文件](#13.2 编写yaml文件)
      • [13.3 加载yaml文件](#13.3 加载yaml文件)
    • [14. 接口测试用例](#14. 接口测试用例)
    • 参考

常见测试框架

java:junit,testng

python:unittest,pytest

复制代码
pip install pytest -U

pytest有三种启动方式:

  1. 命令
  2. 代码
  3. 鼠标

1. 用例结果

1.执行环境:版本、根目录、用例数量

2.执行过程:文件名称、用例结果、执行进度

3.失败详情:用例内容、断言提示

4.整体摘要:结果情况、结果数量、花费时间

缩写 单词 含义
. passed 通过
F failed 失败(用例执行时报错)
E error 出错(fixture执行报错)
s skipped 跳过
X xpassed 预期外的通过(不符合预期)
x xfailed 预期内的失败(符合预期)

2. 用例发现规则

测试框架在识别、加载用例的过程,称之为:用例发现

pytest的用例发现步骤:

1.遍历所有的目录,例外:venv.开头的目录

2.打开python文件,test_开头或者_test结尾

3.遍历所有的Test开头类

4.收集所有的test_开头的函数或者方法

3. 用例内容规则

pytest 8.4 增加了一个强制要求

pytest对用例的要求:

1.可调用的(函数、方法、类、对象)

2.名字test_开头

3.没有参数(参数有另外含义)

4.没有返回值(默认为None)

4. 小测试

main.py

python 复制代码
import pytest

pytest.main()

test_add.py

python 复制代码
import pytest

def add(a,b):
    return a+b

def test_add():
    res=add(1,3)
    assert res==4

def test_add_():
    res=add("1","3")
    assert res=="13"

class TestAdd:
    def test_int(self):
        res=add(1,3)
        assert res==4
    def test_str(self):
        res=add("1","3")
        assert res=="13"
    def test_list(self):
        res=add([1,2,3],4)
        assert res==[1,2,3]
bash 复制代码
============================= test session starts =============================
platform win32 -- Python 3.13.7, pytest-8.4.2, pluggy-1.6.0
rootdir: C:\Users\21609\PycharmProjects\PythonProject1\pytest
plugins: anyio-4.10.0
collected 5 items

test_add.py ....F                                                        [100%]

================================== FAILURES ===================================
______________________________ TestAdd.test_list ______________________________

self = <test_add.TestAdd object at 0x0000025FC14A6D70>

    def test_list(self):
>       res=add([1,2,3],4)
            ^^^^^^^^^^^^^^

test_add.py:20: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

a = [1, 2, 3], b = 4

    def add(a,b):
>       return a+b
               ^^^
E       TypeError: can only concatenate list (not "int") to list

test_add.py:2: TypeError
=========================== short test summary info ===========================
FAILED test_add.py::TestAdd::test_list - TypeError: can only concatenate list...
========================= 1 failed, 4 passed in 0.10s =========================

5. 配置框架

配置可以改变 pytest 默认的规则:

  1. 命令参数
  2. ini文件文件

查看所有的配置方式

复制代码
pytest -h

有哪些配置

  1. -开头:命令行参数
  2. 小写字母开头:ini配置
  3. 大写字母开头:环境变量

配置文件:pytest.ini

常用参数:

-v:增加用例详细内容

-s:在用例中正常的使用输入输出

-x:快速退出,当遇到失败的用例则全部停止执行

-m:用例筛选(pytest -m web)

6. 标记mark

标记可以让用例与众不同,进而可以让用例被区别对待。

1. 用户自定义标记

用户自定义标记只能实现用例筛选。

步骤:

  1. 先注册
  2. 再标记
  3. 后筛选

pytest.ini文件中增加内容:

ini 复制代码
[pytest]

markers =
 api: 接口
 web: UI测试
 Ut: 单元测试
 login: 登录相关
 pay: 支付相关

pytest --markers

修改test_add.py

python 复制代码
class TestAdd:
    @pytest.mark.api
    def test_int(self):
        res=add(1,3)
        assert res==4

    @pytest.mark.web
    def test_str(self):
        res=add("1","3")
        assert res=="13"

    @pytest.mark.UI
    def test_list(self):
        res=add([1,2,3],4)
        assert res==[1,2,3]

只执行web用例

pytest -m web

2. 框架内置标记

框架内置标记可以为用例增加特殊执行效果。

和用户自定义标记区别:

  1. 不需注册,可以直接使用

  2. 不仅可以筛选,还可以增加特殊效果

  3. 不同的标记,增加不同的特殊效果

    • skip:无条件跳过

    • skipif:有条件跳过

    • xfail:预期失败

    • parametrize:参数化

    • usefixtures:使用fixtures

修改test_add.py

python 复制代码
class TestAdd:
    @pytest.mark.skip
    @pytest.mark.api
    def test_int(self):
        res=add(1,3)
        assert res==4

    @pytest.mark.skipif(1==2,reason="跳过了")
    @pytest.mark.web
    def test_str(self):
        res=add("1","3")
        assert res=="13"

    @pytest.mark.xfail()
    @pytest.mark.UI
    def test_list(self):
        res=add([1,2,3],[4])
        assert res==[1,2,3,4]

    @pytest.mark.xfail()
    @pytest.mark.UI
    def test_list_(self):
        res = add([1, 2, 3], [4])
        assert res != [1, 2, 3,4]

7. 数据驱动测试参数

数据驱动测试=参数化测试+数据文件

根据数据文件的内容,动态决定用例的数量、内容

新建data.csv

复制代码
a,b,c
1,1,2
2,3,5
3,3,6
4,4,7

pytest.ini添加ddt: 数据驱动测试

修改test_add.py

python 复制代码
from baifan import readCSV
class TestAdd:
    #其他不变
	@pytest.mark.ddt
    @pytest.mark.parametrize("a,b,c",readCSV("data.csv"))
    def test_ddt(self,a,b,c):
        res=add(int(a),int(b))
        assert res==c

添加baifan.py

python 复制代码
import csv
def readCSV(csvFile):
    with open(csvFile, newline='') as f:
        reader = csv.reader(f)
        return list(reader)[1:]


8. 夹具fixture

夹具:在用例执行之前、执行之后,自动运行代码

场景:

  • 之前:加密参数/之后:解密结果

  • 之前:启动浏览器/之后:关闭浏览器

  • 之前:注册、登录账号/之后:删除账号

1. 创建使用fixture

创建

  1. 创建函数
  2. 添加装饰器
  3. 添加yield关键字

使用

方法1:在用例的参数列表中,加入fixture名字即可

方法2:给用例加上usefixtures标记

新建test_1.py

python 复制代码
import datetime
import pytest

@pytest.fixture
def app():

    print(datetime.datetime.now(),"用例开始执行")
    # 前置操作
    yield
    # 后置操作
    print(datetime.datetime.now(),"用例执行完毕")

def test_1(app):
    pass

@pytest.mark.usefixtures("app")
def test_2():
    pass

pytest -vs

2. 高级用法

  1. 自动使用(所有用例都会使用该fixture)(@pytest.fixture(autouse=True))

  2. 依赖使用(fixture作为参数,一个fixture作为另一个fixture参数)

    • linux:使用linux进行编译
    • git:使用git进行版本控制
    • fixture:使用fixture进行前后置自动操作
  3. 返回内容:接口自动化封装:接口关联

  4. 范围共享

    • 默认范围:function

    • 全局范围:session

test_1.py

python 复制代码
import datetime
import pytest

@pytest.fixture
def ff():
    print("这也是fixture")

@pytest.fixture(autouse=True)
def app(ff):

    print(datetime.datetime.now(),"用例开始执行")
    # 前置操作
    yield 123
    # 后置操作
    print(datetime.datetime.now(),"用例执行完毕")

def test_1():
    pass

def test_2():
    pass

def test_3(app):
    print("接收到传递数据",app)

test_1.py

python 复制代码
def test_1():
    pass

def test_2():
    pass

test_2.py

python 复制代码
def test_3(app):
    print("接收到传递数据",app)

新建C:\Users\21609\PycharmProjects\PythonProject1\conftest.py

python 复制代码
import datetime
import pytest

@pytest.fixture(scope="session")
def ff():
    print("这也是fixture")

@pytest.fixture(autouse=True, scope="session")
def app(ff):

    print(datetime.datetime.now(),"用例开始执行")
    # 前置操作
    yield 123
    # 后置操作
    print(datetime.datetime.now(),"用例执行完毕")

可以看到跨文件传递命名空间和范围共享的效果

9. 插件

1. 插件管理

pytest插件生态是pytest特别的优势之处。

插件分成两类:

  • 不需要安装:内置插件
  • 需要安装:第三方插件

插件的启用管理:

  • 启用:-p abc
  • 禁用:-p no:abc

插件使用方式:

  • 参数
  • 配置文件
  • fixture
  • mark

2. 常用第三方插件

pytest 有1400+插件:https://docs.pytest.org/en/stable/reference/plugin_list.html

pytest-html

用途:生成HTML测试报告

安装:

pip install pytest-html

使用(参数):

pytest --html=report.html --self-contained-html

或者在pytest.ini里面加上

(注意pytest.ini要移动到C:\Users\21609\PycharmProjects\PythonProject1)

复制代码
addopts = --html=report.html --self-contained-html

然后

复制代码
pytest -sv

pytest-xdist

用途:分布式执行(多进程)

安装:

pip install pytest-xdist

使用:

-n N

只有在任务本身耗时较长,超出调用成本很多的时候,才有意义。

分布式执行,有并发问题,资源竞争,乱序。

pytest-rerunfailures

用途:用例失败之后,重新执行

安装:

复制代码
pip install pytest-rerunfailures

使用:

复制代码
--reruns 5 --reruns-delay 1

pytest-result-log

用途:把用例的执行结果记录到日志文件中

安装:

复制代码
pip install pytest-result-log

使用:

ini 复制代码
log_file =./logs/pytest.log
log_file_level= info
log_file_format =%(levelname)-8s %(asctime)s [%(name)s:%(lineno)s]:%(message)s
log_file_date_format = %Y-%m-%d %H:%M:%S

;记录用例执行结果
result_log_enable= 1
;记录用例分制线
result_log_separator= 1
;分制线等级
result_log_level_separator= warning
;异常信息等级
result_log_level_verbose =info

10. 企业级测试报告

allure是一个测试报告框架。

下载allure

https://github.com/allure-framework/allure2/releases

C:\Users\21609\Downloads\allure-2.35.1\bin添加到环境变量

安装

pip install allure-pytest

配置

修改pytest.ini

复制代码
addopts = --alluredir=temps --clean-alluredir

生成报告(命令行,也可以通过python代码来启动)

复制代码
pytest
allure generate -o report -c temps

allure支持对用例进行分组和关联(敏捷开发术语)

复制代码
import allure
@allure.epic  史诗  项目
@allure.feature  主题  模块
@allure.story  故事  功能
@allure.title  标题  用例

修改test_1.py

复制代码
import allure
@allure.epic("a")
@allure.feature("b")
@allure.story("c")
@allure.title("d")
def test_1():
    pass

def test_2():
    pass

11. Web自动化测试

pytest 仅进行用例管理,不会控制浏览器,需要借助新的工具:selenium。

  1. 只了解selenium
  2. 搜索关于selenium的pytest插件

自己实现类似selenium的功能:

pip install pytest-selenium

关闭杀毒软件

修改pytest.ini对应部分

复制代码
addopts = --alluredir=temps --clean-alluredir -m web --driver chrome -vs

test_1.py

python 复制代码
import allure
import pytest
import time

@pytest.mark.web
def test_1(selenium):
    selenium.get("https://www.baidu.com")
    print(selenium.title)

def test_2():
    pass

12. 测试框架要封装什么

封装:

  • 隐藏细节
  • 增加功能
  • 优化功能

接口自动化封装:

  • 使用yaml作为用例,降低自动化门槛
  • 自动请求接口、断言接口
  • 自动在日志记录HTTP报文
  • 自动生成allure测试报告

13. YAML文件格式

一句话:YAML完全兼容JSON格式,并且支持Python相似写法

重点:

  1. YAML完全兼容JSON
  2. 是数据格式,不是编程语言
  3. 像Python一样容易编辑和阅读

13.1 安装yaml文件

pip install pyyaml

13.2 编写yaml文件

  1. #作为注释符号

  2. 缩进:使用2个空格

  3. 成员表示

    • -表示列表成员

    • :表示字典成员

    • null表示空值

    • "666"表示字符串

    • [1,2,3,]表示列表

    • {"a":1,"b":2}表示字典

  4. 兜底:完全兼容JSON

13.3 加载yaml文件

y.py

python 复制代码
import yaml
def Load_yaml():
    f=open("baifan.yaml",encoding="utf-8")#打开文件
    s=f.read()#读取文件内容
    data =yaml.safe_load(s)
    print(data)
    f.close()

Load_yaml()
#{'字典的键': [1, -2, 3.3], '字符串': ['123', '456', 'aaaa']}

baifan.yaml

yaml 复制代码
字典的键:
 - 1
 - -2
 - 3.3

字符串:
  - '123'
  - "456"
  - aaaa

14. 接口测试用例

14.1 请求接口

外部工具:requests

从HTTP协议抓包角度,请求由三部分组成:

  • 行:方法+地址(必填)
  • 头:请求头(键值对)
  • 体:参数内容

14.2 断言响应

  1. 响应里有什么
  2. 响应如何断言

从HTTP协议抓包角度,响应由三部分组成:

  • 行:状态码
  • 头:响应头(键值对)
  • 体:响应内容

14.3 变量的提取

基本原则:

  • JSON:JSONPATH
  • HTML:XPATH
  • 字符串:RE

14.4 框架的落地封装

文件结构,日志,内容

进一步完善:

  • YAML用例测试文件上传?
  • YAML用例进行数据去掉测试?
  • YAML用例进行自定义的断言?
  • YAML用例进行数据库查询?

两个方向:

  • 自动化测试工程师
  • 测试开发工程师

test_api.yaml

yaml 复制代码
name : 登陆成功用例
steps:
  - request : #发送请求
      method : POST
      url : http://116.62.63.211/shop/api.php?application=app&application_client_type=weixin
      params :
        s : user/login
      json : {
        "accounts" : "beifan_1105",
        "pwd" : "beifan_1105",
        "type" : "username"
      }
  - response : #断言响应
      status_code : 200
      json :
        code : 0
        msg : 登录成功
        data :
          username : beifan_1105
  - extract : #提取变量
      token : [ json , $.data.token ]

test_yaml.py

python 复制代码
import json
import re
from unittest import case

import jsonpath
import requests
import responses_validator
from  responses_validator import validator
import allure
import yaml
import pytest

@pytest.mark.api
def test_yaml():
    my_var={}
    with open(r"C:\Users\21609\PycharmProjects\PythonProject1\pytest\test_api.yaml",encoding="utf-8") as f:
        data=yaml.safe_load(f)#打开文件
        allure.title(data['name'])
        for step in data['steps']:
            for k,v in step.items():
                runner(k,v,my_var)

def extract(resp,attr_name,exp):
    try:
        resp.json=resp.json()

    except:
        resp.json={}
    #attr_name为json
    attr=json.loads(json.dumps(getattr(resp,attr_name)))
    #下面的jsonpath需要字符串里面用双引号
    #json.dumps将字典getattr(resp,attr_name)转为json格式字符串,并替换键或者值单引号字符串'name'为双引号字符串"name"
    res=jsonpath.jsonpath(attr,exp)
    print("res",res,resp.json)
    return res[0]


def runner(k,v,my_var):

    match k:
        case "request":
            my_var['resp']=requests.request(**v)
        case "response":
            responses_validator.validator(my_var['resp'],**v)#字典使用2个星号
        case "extract": #变量提取
            for var_name,var_exp in v.items():
                value=extract(my_var['resp'],*var_exp)#列表使用一个星号

pytest.ini

ini 复制代码
[pytest]

addopts = --alluredir=temps --clean-alluredir -m api  -vs

markers =
 api: 接口
 web: UI测试
 Ut: 单元测试
 login: 登录相关
 pay: 支付相关
 ddt: 数据驱动测试

log_file =./logs/pytest.log
log_file_level= info
log_file_format =%(levelname)-8s %(asctime)s [%(name)s:%(lineno)s]:%(message)s
log_file_date_format = %Y-%m-%d %H:%M:%S

;记录用例执行结果
result_log_enable= 1
;记录用例分制线
result_log_separator= 1
;分制线等级
result_log_level_separator= warning
;异常信息等级
result_log_level_verbose =info

响应包如下

复制代码
 {'msg': '登录成功', 'code': 0, 'data': {'id': 23528, 'alipay_openid': '', 'weixin_openid': '', 'weixin_unionid': '', 'weixin_web_openid': '
', 'baidu_openid': '', 'toutiao_openid': '', 'qq_openid': '', 'qq_unionid': '', 'status': 0, 'token': '13d08c2af7fed8e841c0ebc1d7fe8441', 'username': 'beifan_1105', 'nickname': '11
', 'mobile': '', 'email': '', 'gender': 0, 'avatar': 'http://116.62.63.211/shop/public/static/upload/images/user_avatar/compr/2024/11/05/20241105204003902611684.png', 'province': '
', 'city': '', 'birthday': 1731168000, 'address': '', 'integral': 0, 'locking_integral': 0, 'referrer': 0, 'is_delete_time': 0, 'add_time': 1730808873, 'upd_time': 1760245502, 'add_time_text': '2024-11-05 20:14:33', 'upd_time_text': '2025-10-12 13:05:02', 'gender_text': '保密', 'birthday_text': '2024-11-10', 'mobile_security': '', 'email_security': '', 'user_name_view': 'beifan_1105', 'is_mandatory_bind_mobile': 0}}

参考

【B站讲的最好的Pytest自动化测试教程,自动化必备之Pytest测试框架训练营,只需一小时速成,学会直接上手实操!】 https://www.bilibili.com/video/BV1rDdHYCEUP/?p=4\&share_source=copy_web\&vd_source=aeb4f89b7c74bd892c2a834774309409

相关推荐
海琴烟Sunshine3 小时前
leetcode 88.合并两个有序数组
python·算法·leetcode
B站_计算机毕业设计之家4 小时前
数据分析:Python懂车帝汽车数据分析可视化系统 爬虫(Django+Vue+销量分析 源码+文档)✅
大数据·爬虫·python·数据分析·汽车·可视化·懂车帝
Rock_yzh4 小时前
AI学习日记——深度学习
人工智能·python·深度学习·神经网络·学习
DrugOne5 小时前
GAMESS 在 Ubuntu 24.04 平台上的编译与配置
linux·python·ubuntu·drugone
C嘎嘎嵌入式开发6 小时前
(5)100天python从入门到拿捏------流程控制语句
服务器·网络·python
Siren_dream6 小时前
python进阶_Day5
python
nvd116 小时前
python异步编程 -什么是python的异步编程, 与多线程和多进程的区别
python
~~李木子~~6 小时前
用 Python 实现 Gini 决策树分类与可视化-机器学习
python·决策树·机器学习
小黄人软件7 小时前
用AI写的【实时文件搜索引擎】python源码【找资源】
开发语言·python·搜索引擎