写点什么

软件测试 / 测试开发丨 Pytest 测试框架学习笔记分享

作者:测试人
  • 2023-06-06
    北京
  • 本文字数:7021 字

    阅读完需:约 23 分钟

获取更多相关知识

本文为霍格沃兹测试开发学社学员学习笔记分享,文末附原文链接。

一、pytest 结合数据驱动-yaml

1、什么是数据驱动?

数据驱动就是数据的改变从而驱动自动化测试的执行,最终引起测试结果的改变。简单来说,就是参数化的应用。数据量小的测试用例可以使用代码的参数化来实现数据驱动,数据量大的情况下建议大家使用一种结构化的文件(例如 yaml,json 等)来对数据进行存储,然后在测试用例中读取这些数据

2、yaml 文件介绍

1)对象:键值对的集合,用冒号 “:” 表示,在python中为字典
2)数组:一组按次序排列的值,前加 “-”,在python中为列表
3)纯量:单个的、不可再分的值,包括字符串、布尔值、整数、浮点数、Null、时间、日期
复制代码


# {"languages":["PHP","Java","Python"], "book":{"Python入门":{"price": 55.5, "author": "Lily", "available": True, "repertory": 20, "date": "2018-02-17"}, "Java入门": {"price": 60, "author": "Lily", "available": "False", "repertory": "Null", "date": "2018-05-11"}}}languages:  - PHP  - Java  - Pythonbook:  Python入门: # 书籍名称    price: 55.5    author: Lily    available: True    repertory: 20    date: 2018-02-17  Java入门:    price: 60    author: Lily    available: False    repertory: Null    date: 2018-05-11
复制代码

3、查看 yaml 文件

1)pycharm2)txt 记事本
复制代码

4、读取 yaml 文件

1)工程目录结构    ①data 目录:存放 yaml 测试数据文件data.yaml    ②func 目录:存放被测函数文件operation.py    ③testcase 目录:存放测试用例文件test_add.py
2)安装:pip install pyyaml
3)方法:yaml.safe_load(f)
复制代码


# yaml测试数据文件内容# [[1,1,2],[3,6,9],[100,200,300]]-  - 1  - 1  - 2-  - 3  - 6  - 9-  - 100  - 200  - 300
复制代码


# operation.py 文件内容# 被测方法,相加功能def my_add(x, y):    result = x + y    return result

# test_add.py 文件内容import pytestimport yamlfrom testing.func.operation import my_add

# 读取yaml文件def get_data(): """ 获取json数据 :return: 返回数据的结构:[[1, 1, 2], [3, 6, 9], [100, 200, 300]] """ # 如果yaml文件中有中文,必须要加上encoding="utf-8" with open('../data/data.yaml', 'r', encoding="utf-8") as f: data = yaml.safe_load(f) return data

class TestWithYAML: @pytest.mark.parametrize('x,y,expected', get_data()) # 测试数据调用get_data()方法读取出来的数据,需要添加数据时只需在yaml文件即可 def test_add(self, x, y, expected): assert my_add(int(x), int(y)) == int(expected)
复制代码

二、pytest 结合数据驱动-excel

1、安装:pip install openpyxl

2、工程目录结构

①data 目录:存放 excel 测试数据文件params.xlsx②func 目录:存放被测函数文件operation.py③testcase 目录:存放测试用例文件test_excel.py
复制代码


# operation.py 文件内容# 被测方法,相加功能def my_add(x, y):    result = x + y    return result

# test_excel.py 测试用例文件内容import openpyxlimport pytest
from testing.func.operation import my_add

def get_excel(): # 获取工作簿 book = openpyxl.load_workbook('../data/params.xlsx')
# 获取活动行(非空白的) sheet = book.active
# 提取数据,格式:[[1, 2, 3], [3, 6, 9], [100, 200, 300]] values = [] for row in sheet: line = [] for cell in row: line.append(cell.value) values.append(line) return values

class TestWithEXCEL: @pytest.mark.parametrize('x,y,expected', get_excel()) def test_add(self, x, y, expected): assert my_add(int(x), int(y)) == int(expected)
复制代码

三、pytest 结合数据驱动-csv

1、csv 文件介绍

1)csv:逗号分隔值,是 Comma-Separated Values 的缩写2)以纯文本形式存储数字和文本3)文件由任意数目的记录组成4)每行记录由多个字段组成
复制代码

2、csv 文件的使用

1)读取数据    ①内置函数:open()    ②内置模块:csv    ③方法:csv.reader(iterable)
参数:iterable ,文件或列表对象 返回:迭代器,每次迭代会返回一行数据。
2)工程目录结构 ①data 目录:存放csv 测试数据文件demo.csv ②func 目录:存放被测函数文件operation.py ③testcase 目录:存放测试用例文件test_csv.py
复制代码


# csv文件内容1,1,23,6,9100,200,300
# operation.py 文件内容# 被测方法,相加功能def my_add(x, y): result = x + y return result
# 测试用例文件内容import pytestimport csvfrom testing.func.operation import my_add

# 读取csv文件内容def get_csv(): """ 获取csv数据 :return: 返回数据的结构:[[1, 1, 2], [3, 6, 9], [100, 200, 300]] """ with open('../data/demo.csv', 'r') as file: raw = csv.reader(file) data = [] for line in raw: data.append(line) return data

class TestWithCSV: @pytest.mark.parametrize('x,y,expected', get_csv()) def test_add(self, x, y, expected): assert my_add(int(x), int(y)) == int(expected)
复制代码

四、Pytest 结合数据驱动 json

1、json 文件介绍

①json是JS对象,全是JavaScript Object Notation②是一种轻量级的数据交换格式;json 结构
对象 {"key": value}数组 [value1, value2 ...]
复制代码

2、查看 json 文件

①pycharm②txt 记事本
复制代码

3、工程目录结构

①data 目录:存放json数据文件params.xlsx②func 目录:存放被测函数文件operation.py③testcase 目录:存放测试用例文件test_json.py
复制代码

4、读取 json 文件

①内置函数 open()②内置库 json③方法:json.loads()
复制代码


# json数据文件{  "case1": [1, 1, 2],  "case2": [3, 6, 9],  "case3": [100, 200, 300]}
# operation.py 文件内容# 被测方法,相加功能def my_add(x, y): result = x + y return result
# 测试用例文件内容import pytestimport jsonfrom testing.func.operation import my_add

# 读取json文件def get_json(): """ 获取json数据 :return: 返回数据的结构:[[1, 1, 2], [3, 6, 9], [100, 200, 300]] """ with open('../data/param.json', 'r') as f: data = json.loads(f.read()) return list(data.values())

class TestWithJSON: @pytest.mark.parametrize('x,y,expected', [[1, 1, 2]]) def test_add(self, x, y, expected): assert my_add(int(x), int(y)) == int(expected)
复制代码

五、pytest 测试用例生命周期管理

1、Fixture 用法

1)Fixture 特点及优势    ①命令灵活:对于 setup,teardown,可以不起这两个名字    ②数据共享:在 conftest.py 配置⾥写⽅法可以实现数据共享,不需要 import 导⼊。可以跨⽂件共享    ③scope 的层次及神奇的 yield 组合相当于各种 setup 和 teardown    ④实现参数化
2)Fixture 在自动化中的应用- 基本用法 ①使用场景:测试⽤例执⾏时,有的⽤例需要登录才能执⾏,有些⽤例不需要登录。 ②setup 和 teardown ⽆法满⾜。fixture 可以。默认 scope(范围)function ③步骤: a.导⼊ pytest b.在登录的函数上⾯加@pytest.fixture() c.在要使⽤的测试⽅法中传⼊(登录函数名称),就先登录 d.不传⼊的就不登录直接执⾏测试⽅法。
复制代码


import pytest# 定义了登录的fixture,尽量避免以test开头@pytest.fixture()def login():    print("完成登录操作")
def test_search(): print("搜索")
def test_cart(login): # 传入定义了fixture的方法,不需要加括号,执行用例时就会优先执行登录操作 print("购物车")
def test_order(login): # 传入定义了fixture的方法,不需要加括号,执行用例时就会优先执行登录操作 print("下单功能")
复制代码

2、Fixture 在自动化中的应用 - 作用域

【取值:范围:说明】①function:函数级:每一个函数或方法都会调用②class:类级别:每个测试类只运行一次③module:模块级:每一个.py 文件调用一次④package:包级:每一个 python 包只调用一次(暂不支持)⑤session:会话级:每次会话只需要运行一次,会话内所有方法及类,模块都共享这个方法
复制代码


# fixture的作用域import pytest@pytest.fixture(scope="class")def login1():    print("完成登录操作")
def test_search1(): print("搜索")
def test_cart1(login1): # 传入定义了fixture的方法,不需要加括号,执行用例时就会优先执行登录操作 print("购物车")
def test_order1(login1): # 传入定义了fixture的方法,不需要加括号,执行用例时就会优先执行登录操作 print("下单功能")
class TestDemo: def test_case1(self, login1): print("case1")
def test_case2(self, login1): print("case2")
复制代码

3、Fixture 在自动化中的应用 - yield 关键字

1)场景:测试⽅法后销毁清除数据
2)解决:通过在 fixture 函数中加⼊ yield 关键字,yield 是调⽤第⼀次返回结果,第⼆次执⾏它下⾯的语句返回。
3)步骤:
①在@pytest.fixture(scope=module)。 ②在登陆的⽅法中加 yield,之后加销毁清除的步骤
复制代码


import pytest@pytest.fixturedef login():    # setup操作    print("完成登录操作")    # yield相当于return,不添加返回默认为None,可以添加返回值,在yield后面添加,如返回token    token = "abc"    username = "hello"    yield token  # 前面为setup操作,后面为teardown操作    # teardown操作    print("完成登出操作")
def test_search(): print("搜索")
def test_cart(login): # 传入定义了fixture的方法,不需要加括号,执行用例时就会优先执行登录操作 print(f"token:{login}") # 添加返回值时,token为login,拿到token值 print("购物车")
复制代码

4、Fixture 在自动化中的应用 - 数据共享

1)场景:与其他测试⼯程师合作⼀起开发时,公共的模块要在不同⽂件中,要在⼤家都访问到的地⽅。
2)解决:使⽤ conftest.py 这个⽂件进⾏数据共享,并且他可以放在不同位置起着不同的范围共享作⽤。
3)前提:conftest ⽂件名是不能换的,放在项⽬下是全局的数据共享的地⽅
4)执⾏:系统执⾏到参数 login 时先从本模块中查找是否有这个名字的变量什么的,之后在 conftest.py 中找是否有。
5)步骤:将登陆模块带@pytest.fixture 写在 conftest.py文件
复制代码


# conftest.py文件import pytest@pytest.fixture(scope="session")def login():    # setup操作    print("完成登录操作")    # yield相当于return,不添加返回默认为None,可以添加返回值,在yield后面添加,如返回token    token = "abc"    username = "hello"    yield token  # 前面为setup操作,后面为teardown操作    # teardown操作    print("完成登出操作")
@pytest.fixture()def loginDB(): print("连接数据库") yield print("断开数据库连接")
# 新建测试用例文件# 将登录操作放在conftest文件中,且方法需要定义为fixture,实现共享,可以直接调用def test_cart(login): print("购物车")
def test_order(login): print("下单功能")
class TestDemo: def test_case1(self, login, loginDB): # 可以添加多个fixture print("case1")
def test_case2(self, login, loginDB): print("case2")
复制代码

5、Fixture 在自动化中的应用-自动应用

1)场景:    ①不想原测试⽅法有任何改动,或全部都⾃动实现⾃动应⽤,    ②没特例,也都不需要返回值时可以选择⾃动应⽤
2)解决:使⽤ fixture 中参数 autouse=True 实现
3)步骤:在⽅法上⾯加 @pytest.fixture(autouse=True)
复制代码


# conftest.py文件@pytest.fixture(scope="session", autouse=True)def login():    # setup操作    print("完成登录操作")    # yield相当于return,不添加返回默认为None,可以添加返回值,在yield后面添加,如返回token    token = "abc"    username = "hello"    yield token  # 前面为setup操作,后面为teardown操作    # teardown操作    print("完成登出操作")
# 测试用例文件import pytest# conftest文件中登录操作,fixture方法添加参数autouse=True,其他文件调用不需添加login方法名称,可自动生效def test_cart(): print("购物车")
def test_order(): print("下单功能")
复制代码

6、Fixture 在自动化中的应用-参数化

1)场景:测试离不开数据,为了数据灵活,⼀般数据都是通过参数传的
2)解决:fixture 通过固定参数 request 传递
3)步骤: ①在 fixture 中增加@pytest.fixture(params=[1, 2, 3, ‘linda’]) ②在⽅法参数写 request,方法体里面使用 request.param 接收参数
复制代码


import pytest@pytest.fixture(params=[["hali", 123], ["bob", 123456]])def login(request):    print(f"用户名和密码是:{request.param}")    return request.param

def test_case(login): print(f"用户名和密码数据为:{login}"
复制代码

六、pytest 配置文件

1、pytest.ini 是什么

①pytest.ini 是 pytest 的配置文件②可以修改  pytest  的默认行为③不能使用任何中文符号,包括汉字、空格、引号、冒号等等
复制代码

2、pytest.ini 作用

①修改用例的命名规则②配置日志格式,比代码配置更方便③添加标签,防止运行过程报警告错误④指定执行目录⑤排除搜索目录
复制代码

新建一个 pytest.ini 文件,添加以下目录

[pytest];执行check_开头和 test_开头的所有的文件,后面一定要加*python_files = check_* test_*;执行所有的以Test和Check开头的类python_classes = Test*  Check*;执行所有以test_和check_开头的方法python_functions= test_* check_*;-vs打印日志文件,--alluredir ./results 生成报告并存放在results中,执行用例时就不用再该命令了addopts = -vs --alluredir ./results;设置执行的路径testpaths = testing testcase;忽略某些文件夹/目录norecursedirs = result logs datas test_demo*
复制代码

3、日志配置:

1)注意:windows系统 需要把中文 注释去掉。
复制代码


[pytest];日志开关 true falselog_cli = true;日志级别log_cli_level = info;打印详细日志,相当于命令行加 -vsaddopts = --capture=no;日志格式log_cli_format = %(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s);日志时间格式log_cli_date_format = %Y-%m-%d %H:%M:%S;日志文件位置log_file = ./log/test.log;日志文件等级log_file_level = info;日志文件格式log_file_format = %(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s);日志文件日期格式log_file_date_format = %Y-%m-%d %H:%M:%S
复制代码

七、pytest 插件

1、pytest 插件分类

①外部插件:pip install 安装的插件②本地插件:pytest自动模块发现机制,自己编写的插件(conftest.py 存放的)③内置插件:代码内部的_pytest 目录加载
复制代码

2、pytest 常用的插件

(1)pytest-ordering:控制用例的执行顺序

1)场景:对于集成测试,经常会有上下文依赖关系的测试用例。比如 10 个步骤,拆成 10 条 case,这时候能知道到底执行到哪步报错。用例默认执行顺序:自上而下执行2)解决:可以通过 setup,teardown 和 fixture 来解决。也可以使用对应的插件。3)安装:pip install pytest-ordering4)用法:@pytest.mark.run(order=2)5)注意:多个插件装饰器(>2)的时候,有可能会发生冲突
复制代码


import pytest@pytest.mark.run(order=2)def test_case01():    print("case01")
@pytest.mark.run(order=1)def test_case02(): print("case02")
复制代码

(2)pytest-xdist:分布式并发执行测试用例

1)场景:假设有个报名系统,对报名总数统计,数据同时进行修改操作的时候有可能出现问题,需要模拟这个场景,需要多用户并发请求数据。
2)使用分布式并发执行测试用例。分布式插件:pytest-xdist
3)安装及运行: pip install pytest-xdist
4)注意: 用例多的时候效果明显,多进程并发执行,同时支持 allure
5)分布式执行测试用例原则 ①用例之间是独立的,不要有依赖关系 ②用例执行没有顺序,随机顺序都能正常执行 ③每个用例都能重复运行,运行结果不会影响其他用例
6)运行命令 ①pytest -n numcpus :numcpus 是指几核 ②pytest -n auto :不知道是几核时,auto会自动去找空闲的cpu
复制代码

(3)pytest-dependency:控制用例的依赖关系

(4)pytest-rerunfailures:失败重跑

(5)pytest-assume:多重较验

(6)pytest-random-order:用例随机执行

(7)pytest-html:测试报告

3、pytest 内置插件 hook 体系

1)pytest hook介绍
①是个函数,在系统消息触发时被系统调用 ②自动触发机制 ③Hook 函数的名称是确定的 ④pytest 有非常多的勾子函数 ⑤使用时直接编写函数体
复制代码


原文链接:https://ceshiren.com/t/topic/24696

发布于: 刚刚阅读数: 3
用户头像

测试人

关注

专注于软件测试开发 2022-08-29 加入

霍格沃兹测试开发学社,测试人社区:https://ceshiren.com/t/topic/22284

评论

发布
暂无评论
软件测试/测试开发丨Pytest测试框架学习笔记分享_程序员_测试人_InfoQ写作社区