1、Pytest是什么?
- Pytest支持简单的单元测试和复杂的功能测试;
- Pytest结合Request实现接口测试;
- Pytest结合selenium、appium实现自动化功能测试;
- Pytest结合allure和jenkins,可以实现生成美观的测试报告,持续集成;
- pytest支持315种以上的插件;
2、为什么选择Pytest?
- 简单灵活
- 兼容unittest
- 可定制化插件开发
3、Pytest环境安装
前置条件:完成python环境安装
- 方式1:
通过命令安装:
pip install pytest
查看已安装第三方库:
pip list
- 方式2:
在python开发工具pycharm中安装;
pycharm菜单选择file->setting,然后选择Project***->python interpreter,点击+号,可添加python第三方插件pytest;
4、第一个脚本
脚本:test_sample.py
def inc(x):
return x + 1
def test_answer(self):
assert self.inc(3) == 5
执行:
在dos窗口执行
输入命令:pytest test_sample.py
执行结果:
5、Pytest格式要求
- 文件
以test_开头或者以_test结尾;
- 类
以Test开头,驼峰命名法,首字母大写;
- 方法/函数
以test_开头;
6、Pycharm配置
配置pycharm默认执行器为pytest(pycharm默认执行器为unittest)
菜单选择:file->setting,python integrated tool菜单下default test runner选择【pytest】;
7、运行用例
脚本test_sample.py
class TestDemo():
def inc(x):
return x + 1
def test_answer(self):
assert self.inc(3) == 5
def test_first(self):
print("first...")
1)运行当前目录下所有符合pytest规则的脚本用例
语法:pytest
pytest
2)运行指定的脚本
语法:pytest 脚本名称
pytest test_sample.py
3)运行指定脚本某个类下的所有用例
语法:pytest 脚本名::类名
pytest test_sample.py::TestDemo
4)运行某个脚本某个类下的指定方法
语法:pytest 脚本名::类名::方法名
pytest test_sample.py::test_answer
8、Pytest测试框架结构
样例:
#模块级别,只被调用1次
def setup_module():
print("setUp module")
def teardown_module():
print("tearDown module")
class TestDemo1:
#类级别,在类里只调用1次
def setup_class(self):
print("setUp class TestDemo01")
#方法级别,在每个方法调用1次
def setup(self):
print("setUp 方法")
def teardown(self):
print("teardown 方法")
def test_case01(self):
print("TestDemo01:test case01")
def test_case02(self):
print("TestDemo01:test case02")
def teardown_class(self):
print("tearDown class TestDemo01")
class TestDemo2:
def setup_class(self):
print("setUp class TestDemo02")
def test_case01(self):
print("TestDemo02:test case01")
def test_case02(self):
print("TestDemo01:test case02")
def teardown_class(self):
print("tearDown class TestDemo02")
9、命令行参数
- –help:查看帮助
- -x:用例一旦失败,立刻停止,不再继续往下执行
- –maxfail=num:允许失败的用例数,num=3表示允许失败2条用例,当失败3条用例,立刻停止不再往下执行;
- -k:执行包含某个关键字的测试用例
- -v:打印详细信息
- -s:打印输出日志(一般-vs一块使用)
- –collect-only:收集用例不执行
- –lf:只重新运行上一次失败的用例,若上一次无失败的用例,则执行全部用例
- –ff:先运行失败的用例,然后执行其他用例
10、标记测试用例
10.1 执行指定标签的用例
- 应用场景:
只执行符合要求的某一部分用例;把项目划分为多个模块,然后指定模块名称执行用例;
- 方法:
在测试用例方法上添加@pytest.mark.标签名;
在执行的时候通过-m参数执行指定标签的模块;
说明:如果标签名不是pytest内置标签,需要通过新建pytest.ini文件,添加标签名,否则执行结果会出现警告信息;
样例:
pytest -s test_mark_zi_09.py -m apptest
pytest -s test_mark_zi_09.py -m "not ios"
10.2 跳过指定用例
- 应用场景:
调试时不想运行的用例
标记无法在某些平台上运行的用例
在某些版本中执行,其他版本跳过不执行的用例
- 方法:
1)添加装饰器
在用例前添加装饰器
@pytest.mark.skip(reason=“原因,可自定义”):全部跳过用例
@pytest.mark.skipif(条件,原因):条件满足,跳过用例
2)用例中跳过
在测试用例中添加代码跳过用例
pytest.skip(“原因,自定义”)
11、参数化
为更真实的模拟测试场景,对测试数据进行参数化,模拟多种不同的情况;
- 方法:
在用例前添加装饰器
@pytest.mark.parametrize(“参数1,参数2…”,[(第一组数据),(第二组数据),(第三组数据),…],ids=[“第一次用例名称”,“第二次用例名称”,“第三次用例名称”,…])
说明:
1)装饰器中的参数名称要和用例中的参数名称保持一致;
2)当参数包含单个参数值时,参数值要放在列表中;
3)ids用于重命名执行用例的名称,ids的个数要与参数值的个数一致,ids可以省略,当ids为空时,默认使用参数值作为执行用例的名称;
样例:
import pytest
data=[("zhangsan","123456"),("","123456"),("wangwu","")]
@pytest.mark.parametrize("user,pwd",data,ids=["正确账号密码","空用户名","空密码"])
def test_login(user,pwd):
print(user,pwd)
- 笛卡尔积
当测试用例包含多个参数n,每个参数有多个参数值m,为覆盖所有测试用例,参数的组合就是n*m,所有参数的组合就是笛卡尔积;
样例:
两个参数wd和code,每个参数包含3个参数值,测试用例的组合为9个;
import pytest
data1 = ["appium","selenium","pytest"]
data2 = ["utf-8","gbk","gb2312"]
@pytest.mark.parametrize("wd",data1)
@pytest.mark.parametrize("code",data2)
def test_dkej(wd,code):
print(f"wd:{wd},code:{code}")
执行结果:
12、使用python执行pytest测试用例
12.1 使用main函数执行
- 语法:
1)运行目录下所有测试用例
pytest.main()
2)运行指定文件下的指定用例
pytest.main(['脚本名::测试用例名','命令参数'])
3)运行指定文件下的指定标签用例
pytest.main(['脚本名','-vs','-m','标签名'])
样例:
import pytest
if __name__=='__main__':
#运行目录下所有测试用例
#pytest.main()
#运行指定文件下的指定用例
#pytest.main(['test_parametrizeTest02.py::test_dkej','-vs'])
#运行指定文件下的指定标签用例
pytest.main(['test_markTest.py','-vs','-m','str'])
12.2 通过命令行调用
通过命令调用:python -m pytest 脚本名
样例:
python -m pytest test_sample.py
13、异常处理
正常情况下,发生异常后,异常后的代码不会被执行,为保证发生异常后,代码仍能够正常执行,需要对异常进行处理;
13.1 try-except
除数为0异常,当除数为0时进行异常处理;try内为正常处理代码,except内为异常处理代码;
try:
a=int(input("请输入除数"))
b=int(input("请输入被除数"))
c=a/b
print("结果:",c)
except(ArithmeticError):
print("除数不可为0")