霍格沃兹测试开发学社

扫码领取本节相关资料

Pytest 测试框架

霍格沃兹测试开发学社 ceshiren.com

前言

  • 自动化测试前,需要提前准备好数据,测试完成后,需要自动清理脏数据,有没有更好用的框架?
  • 自动化测试中,需要使用多套测试数据实现用例的参数化,有没有更便捷的方式?
  • 自动化测试后,需要自动生成优雅、简洁的测试报告,有没有更好的生成方法

Pytest 背景与优势

Pytest 是什么?

  • pytest 能够支持简单的单元测试和复杂的功能测试;
  • pytest 可以结合 Requests 实现接口测试; 结合 Selenium、Appium 实现自动化功能测试;
  • 使用 pytest 结合 Allure 集成到 Jenkins 中可以实现持续集成。
  • pytest 支持 315 种以上的插件;

为什么要选择 Pytest

  • 丰富的第三方插件
    • 报告
    • 多线程
    • 顺序控制

pytest

pytest pytest

为什么要选择 Pytest

  • 简单灵活
# content of test_sample.py
def inc(x):
    return x + 1


def test_answer():
    assert inc(3) == 5

为什么要选择 Pytest

  • 兼容 unittest
  • 定制化插件开发

pytest

pytest

扫码领取本节相关资料

Pytest 安装与准备

Pytest 环境安装

  • 前提:本地已配置完成Python环境
  • 第一种方式 pip install pytest
  • 第二种方式 PyCharm 直接安装

运行第一个脚本

# content of test_sample.py
def inc(x):
    return x + 1


def test_answer():
    assert inc(3) == 5

实操

  • 1、创建目录 Desktop(桌面)/pytestdemo1
  • 2、创建文件 test_first.py
  • 3、打开【terminal】 /【命令提示行cmd】
  • 4、运行 pytest 回车

扫码领取本节相关资料

Pytest 命名规则

Pytest 有哪些格式要求?

  • 文件名
  • 方法/函数

Pytest 测试用例编写规则是什么?

类型 规则
文件 test_开头 或者 _test 结尾
Test 开头
方法/函数 test_开头
注意:测试类中不可以添加__init__构造函数

练习

  • (多选)下面哪个测试方法,符合 pytest 命名规范
    • A、测试类 TestDemo
    • B、测试方法 test_demo
    • C、测试文件 testdemo
    • D、测试包 test_demo

扫码领取本节相关资料

pycharm 配置与界面化运行

Pycharm 界面化安装 Pytest

pytest

Pycharm 默认测试执行器为Pytest

  1. 进入 Tools->Python Intergrated Tools
  2. 选择 Default test runner 为 pytest

pytest

扫码领取本节相关资料

运行用例

运行多条用例

  • 运行 某个/多个 用例包
  • 运行 某个/多个 用例模块
  • 运行 某个/多个 用例类
  • 运行 某个/多个 用例方法

运行多条用例方式

  • 执行包下所有的用例:pytest/py.test [包名]
  • 执行单独一个pytest模块:pytest 文件名.py
  • 运行某个模块里面某个类:pytest 文件名.py::类名
  • 运行某个模块里面某个类里面的方法:pytest 文件名.py::类名::方法名

运行结果分析

  • 常用的:fail/error/pass
  • 特殊的结果:warning/deselect(后面会讲)

扫码领取本节相关资料

Pytest 测试框架结构(setup/teardown)

测试装置介绍

类型 规则
setup_module/teardown_module 模块级,整个模块的所有测试用例执行前后运行一次
setup_class/teardown_class 类级,只在类中前后运行一次
setup_function/teardown_function 函数级,在类外每个测试用例执行前后被调用
setup_method/teardown_methond 方法级,类中的每个测试用例执行前后
setup/teardown 方法级,类中的每个测试用例执行前后(重点)

扫码领取本节相关资料

常用命令行参数

命令行参数 - 常用命令行参数

—help 
-x   用例一旦失败(fail/error),就立刻停止执行
--maxfail=num 用例达到 
-m  标记用例
-k  执行包含某个关键字的测试用例
-v 打印详细日志
-s 打印输出日志(一般-vs一块儿使用)
—collect-only(测试平台,pytest 自动导入功能 )

命令行参数-使用缓存状态

  • --lf(--last-failed) 只重新运行故障。
  • --ff(--failed-first) 先运行故障然后再运行其余的测试

扫码领取本节相关资料

使用 Mark 标记测试用例

Mark:标记测试用例

  • 场景:只执行符合要求的某一部分用例 可以把一个web项目划分多个模块,然后指定模块名称执行。
  • 解决: 在测试用例方法上加 @pytest.mark.标签名
  • 执行: -m 执行自定义标记的相关用例
    • pytest -s test_mark_zi_09.py -m=webtest
    • pytest -s test_mark_zi_09.py -m apptest
    • pytest -s test_mark_zi_09.py -m "not ios"

Mark:跳过(Skip)及预期失败(xFail)

  • 这是pytest 的内置标签,可以处理一些特殊的测试用例,不能成功的测试用例
  • skip - 始终跳过该测试用例
  • skipif - 遇到特定情况跳过该测试用例
  • xfail - 遇到特定情况,产生一个“期望失败”输出

Skip 使用场景

  • 调试时不想运行这个用例
  • 标记无法在某些平台上运行的测试功能
  • 在某些版本中执行,其他版本中跳过
  • 比如:当前的外部资源不可用时跳过
    • 如果测试数据是从数据库中取到的,
    • 连接数据库的功能如果返回结果未成功就跳过,因为执行也都报错
  • 解决1:添加装饰器
    • @pytest.mark.skip
    • @pytest.mark.skipif
  • 解决2:代码中添加跳过代码
    • pytest.skip(reason)

xfail 使用场景

  • 与skip 类似 ,预期结果为fail ,标记用例为fail
  • 用法:添加装饰器@pytest.mark.xfail

参数化

参数化设计方法就是将模型中的定量信息变量化,使之成为任意调整的参数。

对于变量化参数赋予不同数值,就可得到不同大小和形状的零件模型。

Mark:参数化测试函数

  • 测试场景
    • 测试登录成功,登录失败(账号错误,密码错误)
    • 创建多种账号: 中⽂文账号,英⽂文账号
  • 普通测试用例方法
    • Copy多份代码 or 读⼊入参数?
    • 一次性执⾏多个输⼊入参数
  • pytest参数化实现方法
    • @pytest.mark.parametrize进行参数化和数 据驱动更灵活

Mark:参数化测试函数使用

  • 单参数
  • 多参数
  • 用例重命名
  • 笛卡尔积

参数化:单参数情况

search_list = ['appium','selenium','pytest']

@pytest.mark.parametrize('name',search_list)
def test_search(name):
    assert name in search_list

参数化:多参数情况

@pytest.mark.parametrize("test_input,expected",[
    ("3+5",8),("2+5",7),("7+5",12)
])
def test_mark_more(test_input,expected):
    assert eval(test_input) == expected

参数化:用例重命名-添加ids参数

@pytest.mark.parametrize("test_input,expected",[
    ("3+5",8),("2+5",7),("7+5",12)
],ids=['add_3+5=8','add_2+5=7','add_3+5=12'])
def test_mark_more(test_input,expected):
    assert eval(test_input) == expected

参数化:笛卡尔积

  • 比如

    • `a= [1,2,3]
    • b=[a,b,c] `
  • 有几种组合形势 ?

    • (1,a),(1,b),(1,c)
    • (2,a),(2,b),(2,c)
    • (3,a),(3,b),(3,c)