1.pytest单元测试框架
1)什么是单元测试框架
单元测试是指在软件开发中,针对软件的最小单位(函数,方法)进行正确性的检查测试。
2)单元测试框架
Java:junit,testng
python:unittest,pytest
3)单元测试框架主要做什么?
1.测试发现:从多个文件中找到我们的测试文件,用例;
2.测试执行:按照一定的顺序和规则去执行,并生成结果;
3.测试判断:通过断言判断预期结果和实际结果的差异;
4.测试报告:统计测试进度,耗时,通过率,生成测试报告。
2.自动化测试框架和单元测试框架的关系。
1)什么是自动化测试框架
2)作用
1.提高测试效率,降低维护成本;
2.减少人工干预,提高测试的准确性,增加代码的复用性;
3.核心思想是让不懂代码的人也能通过该框架,轻松完成测试。
3)pytest单元测试框架和自动化测试框架的关系
单元测试框架:只是自动化测试框架的组成部分之一;
pom设计模式:只是自动化测试框架的组成部分之一。
数据驱动
关键字驱动
全局配置文件的封装
日志监控
selenium,requests二次封装
断言
报告邮件
更多。。。。。。
3.pytest简介
1)pytest是一个非常成熟的python单元测试框架,比unittest更灵活,上手;
2)pytest可以和selenium,requests,appnium结合实现web自动化,接口自动化,app自动化测试;
3)pytest可以实现用例的跳过,错误用例的resuns;
4)pytest可以结合allure生成非常美观的测试报告;
5)pytest可以和jenkins持续集成;
6)pytets有很多强大的插件,并且这些插件能够实现很多非常有用的操作;
pytest
pytest-html 生成html格式的自动化测试报告;
pytest-xdist 测试用例分布式执行,多cpu分发;
pytest-ordering 改变测试用例的执行顺序;
pytest-rerunfailures 用例失败重跑;
allure-pytest 用于生成优美的报告。
pycharm快捷安装,将上述包报道requirements.txt文件中,通过terminal 执行:pip install -r requirements.txt
检查安装完成:pytest --version
4.待定
1)模块名必须以test_开头或以_test结尾;
2)测试类必须以Test开头,且不能有init方法;
3)测试方法必须以test开头。
5.pytest测试用例的运行方式
1).主函数模式
1.运行所有:pytest.main()
2.指定模块:pytest.main([’-vs’, ‘test_login.py’])
3.指定目录:pytest.main([’-vs’,’./interface_testcase’])
4.通过nodeid指定测试用例执行:nodeid由模块名,分隔符,类名,方法名,函数名组成。
pytest.main([’-vs’, ‘./interface_testcase/test_interface.py::test_04_func’])
pytest.main([’-vs’, ‘./test_interface/test_interface.py::Testinterface::test_03_zhidao’])
2)命令行模式
1.运行所有:pytest
2.指定模块:pytest -vs ./test_login.py
3.指定目录:pytest -vs ./test_intestface
4.指定目录:pytest -vs ./test_inteface/test_interface.py::test_04_func
3)py.test 参数 脚本
4)python -m pytest 参数 脚本
注:参数详解:
-s: 表示输出调试信息,包括print打印信息;
-v: 显示更详细信息;
-vs:两参数一起用。
-q:以极简方式运行;
-n::支持多线程或者分布式执行用例;
如:pytets -vs ./test_case -n 2
pytest.main(['-vs', './test_case', '-n=2'])
--reruns NUM :失败用例重跑;
-x: 只要出现一个用例报错,全部都停止;
--maxfail=2:出现两个用例失败就停止;
-k: 测试包含指定字符串用例;
例:pytest -vs ./test_case -x "ao"
--html ./report/report.html :生成html测试报告
3)通过读取pytest.ini配置文件运行
pytest.ini是pytest单元测试框架的核心配置文件;
1.位置:一般放在项目的根目录;
2.编码:必须是ANSI,可以使用notepad++修改编码格式;
3.作用:改变pytest的默认行为;
4.运行规则:不管是主函数的运行,命令模式运行,都会读取这个配置文件。
[pytest]
addopts = -vs
testpaths = ./test_case
python_files = test_*.py
python_clasees = Test
python_functions = test
markers =
smoke:冒烟用例
usermanage:用户管理模块
productmanage:商品模块管理
6.pytest执行用例的顺序是怎么样的呢?
unittest 是ascll的大小决定执行的顺序;
pytest默认从上倒下;
改变默认执行顺序:使用mark 标记;
例子: @pytest.mark.run(order=3)
7.如何分组执行(冒烟,分模块执行,分接口和web执行)
smoke:冒烟用例,分布在各个模块里面;
pytest.ini文件中添加相关markers
命令行执行:
pytest -m “smoke”
pytest -m “smoke or usermanage”
8.pytest跳过测试用例
1)无条件的
@pytest.mark.skip
2)有条件的
@pytest.mark.skipif(num >= 20, reason=“太大了”)
9.pytest结合allure-pytest插件生成allure报告
1.下载,解压,配置环境变量path路径;
请提前安装好jdk,并配置好环境变量!!!
https://github.com/allure-framework/allure2/releases
验证:allure --version
问题:dos可以验证,pycharm验证不了,建议重启pycharm
2.加入命令,生成临时json报告;
–alluredir ./temp
3.生成allure报告
os.system(‘allure generate ./temp -o ./report --clean’)
allure generate 命令,固定的
./temp 临时的json报告路径
-o 输出output
./report 生成的allure报告的路径
–clean 清空。./report路径原来的报告
10. @pytest.mark.parametrize(args, value)用法
args:参数名称
value:值(列表,元组,字典列表,字典元组),有多少值,用例就执行多少次。
第一种方式:
import pytest
class TestApi:
@pytest.mark.parametrize('args', ['haha', 'keke', 'xixi'])
def test_ala(self, args):
print(args)
if __name__ == '__main__':
pytest.main()
第二种方式:类似u’nittest中ddt的@unpack解包
import pytest
class TestApi:
@pytest.mark.parametrize('name, age', [['dad', 18], ['xiuxiu', 19], ['lula', 20]])
def test_ala(self, name, age):
print(name, age)
if __name__ == '__main__':
pytest.main()
11.前置后置
1.模块级,作用范围为当前模块,模块中的所有用例执行前后分别执行1次前置后置:
setup_module(),前置,所有用例执行前执行一次;
teardown_module(),后置,所有用例执行后执行一次。
import pytest
def setup_module():
print("\n这是前置!")
def teardown_module():
print("\n这是后置!")
@pytest.mark.parametrize('a', [1, 2, 3, 4, 5])
def test_f(a):
print(a)
if __name__ == '__main__':
pytest.main(['-s', __file__])
2.函数级,作用范围为当前模块中的每一个测试函数,模块中的每条用例执行前后分别执行一次;
setup_function(),前置,每条用例执行前执行一次;
teardown_function(),后置,每条用例执行后执行一次。
3.函数级,作用范围为当前类,类中的所有用例执行前后分别执行一次;
setup_class(),前置,所有用例执行前执行一次;
teardown_class(),后置,所有用例执行后执行一次。
import pytest
class Test:
def setup_class(self):
print("\n这是前置!")
def teardown_class(self):
print("\n这是后置!")
@pytest.mark.parametrize('a', [1, 2, 3, 5])
def test_p(self, a):
print(a)
if __name__ == '__main__':
pytest.main(['-s', __file__])
4.方法级,作用范围为当前类中的每一个测试方法,每条用例执行前后分别执行一次前置和后置;
setup_method()或者setup(),前置,每条用例执行前执行一次;
teardown_method()或者teardown(),后置,每条用例执行后执行一次。
5.fixture
1.创建: @pytest.fixture([name, scope, params, autouse])
name: 指定fixture名称, 如果不指定则默认为被装饰的函数名;
scope: 指定fixture的作用范围,module,class,function(默认),session,package;
params:参数
autouse:设置为True,实现自动调用fixture。
例子1:
import pytest
# 创建fixture
@pytest.fixture(name='fx', scope='module', autouse=True)
def login():
print("这是登录!")
yield "注销" # 通过yield实现后置
def test_add(fx):
a = fx
print("添加会员!")
print(a)
def test_qurey():
print("这是查询!")
if __name__ == '__main__':
pytest.main(['-vs', __file__])
2.全局fixture
在项目目录下创建conftest.py文件,在该文件中实现fixture。
例子待更新。。。。。
11.yaml文件详解–实现自动化
1.用于全局的配置文件ini/yaml
2.用于写测试用例(接口测试用例)
注意:安装pyyaml包
yaml简介:
yaml是一种数据格式,支持换行,注释,多行字符串,裸字符串(整形,字符串)。
语法规则:
1.区分大小写;
2.使用缩进表示层级,不能使用tab键缩进,只能使用空格(和python一样);
3.缩进没有数量的,只要前面是对齐的就行;
4.注释是#
数据组成:
1.map对象,键值对,键:(空格)值;
多行写法:
resp:
name: dada
age: 18
单行写法
resp: {name: dada,age: 18}
2.数组list用一组横线开头,如:
多行写法:
-
resp:
- name: dada
- age: 18
单行写法:
-
resp: [{name:dada},{age: 18}]
3.编写完ymal文件,需要编写相应的py文件进行解析,获取yaml文件内容,例如YamlUtil.py
import yaml
class YamlUtil:
def __init__(self, yaml_file):
"""
指定读取文件
:param yaml_file:
"""
self.yaml_file = yaml_file
def read_yaml(self):
"""
读取yaml文件
:return:
"""
with open(self.yaml_file, encoding='utf-8') as f:
value = yaml.load(f, Loader=yaml.FullLoader)
print(value)
if __name__ == '__main__':
YamlUtil('test_api.yaml').read_yaml()
12.接口自动化测试
1.以百度查询大象页面为例,本问去掉其他相关参数,只添加 搜索关键字wd,
url = ‘https://www.baidu.com/s?’
wd = “大象” # 可能需要进行utf-8编码
test_api.yaml如下:
-
name: 测试百度查询大象
request:
url: https://www.baidu.com
method: get
params:
wd: 大象
headers:
Content-Type: application/json
validate:
- eq: {code: 200}
yaml_util.py文件内容如下:
import yaml
class YamlUtil:
def __init__(self, yaml_file):
"""
指定读取文件
:param yaml_file:
"""
self.yaml_file = yaml_file
def read_yaml(self):
"""
读取yaml文件
:return:
"""
with open(self.yaml_file, encoding='utf-8') as f:
value = yaml.load(f, Loader=yaml.FullLoader)
return value
测试case:test_da.py内容如下:
#!encoding:utf-8
import pytest
import requests
from yaml_util import YamlUtil
class TestDax:
@pytest.mark.parametrize('args', YamlUtil('test_api.yaml').read_yaml())
def test_daxiang(self, args):
print(args)
url = args['request']['url']
wd = str(str(args['request']['params']['wd']).encode(encoding='utf-8'))[1:].upper() # 关键字编码,或许可省略,没尝试
args['request']['params']['wd'] = wd
params = args['request']['params']
resp = requests.get(url, params)
print(resp.status_code)
print(resp.text)
assert resp.status_code == args['validate'][0]['eq']['code']
然后使用上文提到创建的test_main相关文件执行,结果图如下: