pytest单元测试框架

什么是单元测试框架

单元测试是指在软件开发中,针对软件的最小单位(函数、方法)进行正确性的检查测试

常见的单元测试框架

java:Junit

python: unittest和pytest

单元测试框架主要做什么

  1. 测试发现:从多个文件里面去找到我们的测试用例
  2. 测试执行:按照一定的顺序和规则去执行,并生成结果
  1. 测试判断:通过断言判断预期结果和实际结果的差异
  2. 测试报告:统计测试进度,耗时,通过率,生成测试报告

单元测试框架和自动化测试框架的关系

自动化测试框架的作用:

  • 提高测试效率,降低维护成本
  • 减少人工干预,提高测试的准确性,增加代码的重用性
  • 核心思想是让不懂代码的人,也能够通过这个框架去实现自动化测试
  • 单元测试框架只是自动化测试框架的组成部分之一

自动化测试框架包含以下内容:

  1. 单元测试框架
  2. pom设计模式
  3. 数据驱动
  4. 关键字驱动
  5. 全局配置文件的封装
  6. 日志监控
  7. selenium,request的二次封装
  8. 断言
  9. 报告邮件
  10. 更多。。。

pytest简介

  • 是一个非常成熟的python的单元测试框架,比unittest更灵活,容易上手
  • 可以和selenium、requests、appium结合实现web自动化,接口自动化,APP自动化
  • 可以实现测试用例的跳过和重试
  • 可以和allure生成非常美观的测试报告
  • 可以和Jenkins持续集成
  • 有很多强大的插件:
     

使用命令:pip install -r .\pytest\plugiininstall.txt 安装插件

plugiininstall.txt文件

pytest
pytest-html
pytest-xdist
pytest-ordering
pytest-rerunfailures
allure-pytest
  •  pytest-html(生成HTML格式的自动化测试报告)
  • pytest-xdist(测试用例分布式执行,多CPU分发)
  • pytest-ordering (用于改变测试用例的执行顺序)
  • pytest-rerunfailures(用例失败后重跑)
  • allure-pytest(用于生成美观的测试报告)
     

pytest使用的命名规则

  1. 模块名必须以test_开头或者_test结尾
  2. 测试类必须以Test开头,并且不能有init方法
  3. 测试方法必须以test开头

 pytest测试用例的运行方式

  • 主函数模式(if __name__ == '__main__':)
  • 运行所有:pytest.main()(使用单独的py文件来运行)
  • 指定模块:pytest.main(['-vs', 'test_print.py'])(使用单独的py文件来运行)
  • 指定目录:pytest.main(['-vs', './interface_testcase'])(使用单独的py文件来运行)
  • 通过nodeid指定用例运行:nodeid由模块名,分隔符,类名,方法名,函数名组成。 pytest.main(['-vs', './interface_testcase/test_interface.py::TestInterface::test_01_demo'])(使用单独的py文件来运行)
     
  • 命令行模式
  • 运行所有:pytest
  • 指定模块:pytest -vs test_print.py
  • 指定目录:pytest -vs ./interface_testcase
  • 通过nodeid指定用例运行:pytest -vs ./interface_testcase/test_interface.py::TestInterface::test_01_demo
     
  1. 通过读取pytest.ini核心配置文件运行

  • 位置:项目的跟目录下
  • 编码:必须是ANSI,可以使用notepad++改变编码格式
  • 作用:改变pytest的默认行为
  • 运行的规则:不管是主函数的模式运行,还是命令行的模式运行,都会去读取这个配置文件
[pytest]
addopts= -vs
test_paths =./pytest01
python_files=test_*.py
python_classes=Testa*
python_functions=test

pytest参数详解

  • -s: 表示输出调试信息,包括打印信息
  • -v: 表示输出更详细信息
  • -n: 支持多线程运行测试用例。如:pytest -vs test_print.py -n 2

pytest.main(['-vs', './interface_testcase','-n=2'])

  • --reruns:失败用例重跑,--reruns=2

pytest.main(['-vs', './interface_testcase','--reruns=2'])

  • -x: 表示只要有一个用例报错,那么测试停止。
  • --maxfail=2:出现两个用例失败就停止
  • -k: 执行包含指定字符串的测试用例:pytest -vs test_print.py -k "ao"
  • --html ./report/report.html:生成报告
  • -m:分组执行

pytest执行测试用例的顺序

unittest:是通过ASCII的大小来执行的顺序

pytest:默认是按照从上到下的顺序执行

改变默认的执行顺序:使用mark标记,order代表第几个执行

@pytest.mark.run(order=1)

如何分组执行

分组执行的常用场景:冒烟、分模块执行、分接口和web执行

pytest.ini 

[pytest]
addopts= -vs
test_paths =./pytest01
python_files=test_*.py
python_classes=Testa*
python_functions=test
markers=
    smoke:冒烟用例
    usermanage:用户管理模块
    productmanage:商品管理模块

 在要执行的用例上面标明是哪个分组:

@pytest.mark.usermanage
def test_01_baili(self):
    print('测试百里')

@pytest.mark.smoke
def test_02(self):
    print('测试2')
pytest -vs -m "smoke"
pytest -vs -m "smoke or usermanage"

如何跳过执行某个测试用例

# 无条件跳过
@pytest.mark.skip
# 有条件跳过,必须带reason
# @pytest.mark.skipif(age == 18, reason='未成年')
def test_03(self):
    print('测试3')

接口自动化

目前主流的接口测试的工具:

postman+newman+git/svn+jenkins

jmeter+ant+git/svn+jenkins

弊端:

  • 敏捷开发时代,接口数量巨大,工具无法做到团队协作和版本控制
  • 功能写死了,对于一些复杂的接口(自定义加密和签名接口)
  • 项目里面有多种协议接口:http、webservice、websocket、dubbo
  • 排错,定位问题
  • 没有完整的测试报告
  • 多接口串联,数据库连接,日志监控
  • 有些公司即要做接口自动化,又要做web自动化,接口+web结合

request库

python第三方库,主要用于接口自动化测试

pip install requests

请求方法

请求头:

  • Content-Type: 传值的内容格式
  • application/x-www-urlencoded:表单
  • mutipart/form-data:表单里面有文件上传
  • text/plain:文本
  • binary:二进制文件
  • Accept:客户端接收数据的格式
  • X-Requested-With:异步请求
  • User-Agent:客户端的用户类型
  • Cookie:cookie信息
  • get(url, params=None, **kwargs)
  • 通过params进行传参
  • post(url, data=None, json=None, **kwargs)
  • 通过data传参,
  • 参数是dict类型:请求头的Content-Type:application/x-www-urlencoded,表示通过表单传参,格式a=1&b=2
  • 参数是str类型:Content-Type:text/plain
  • 通过json传参,请求头的Content-Type:applicaiton/json,格式{"a":1}
  • request(method, url, **kwargs):
  • method:请求方法类型
  • url:请求地址
  • kwargs:字典类型的可变参数
  • params=,表示get方法传参
  • data=,表示post方法传参
  • json=,表示json方法传参
  • headers=,表示请求头
  • cookies=,表示cookie关联
  • files=,表示文件上传

响应

res = requests.get(url, params)

print(res.json())  # 把返回值转换为一个dict对象
print(res.text)  # 转换为文本
print(res.content)  # 转换为字节类型的数据
print(res.status_code)  # 返回码
print(res.reason)  # 返回信息
print(res.cookies)  # cookie信息
print(res.encoding)  # 编码格式
print(res.headers)  # 响应头
print(res.request)  # 请求对象request

 json和dict互转

json.load()  # dict=====>json
json.dumps()  # json===>dict

 

pytest.fixture

@pytest.fixture(scope="作用域", params="数据驱动", autouse="自动执行", ids="数据驱动时重命名参数名", name="给fixture作用的函数的重命名")

scope参数:
function:函数
class:类
module:模块
package/session:会话

 作用在方法前后

# scope="function":表明作用在方法前后
@pytest.fixture(scope="function")
def exec_database_sql():
    print("前置操作-===数据库查询")
    yield
    print("后置操作=====数据校验")
    

# 指定要使用的fixture固件:exec_database_sql
def test_05(self, exec_database_sql):
	print('测试5')    
    
# 输出为以下内容
前置操作-===数据库查询
测试5
PASSED后置操作=====数据校验

作用在类前后

@pytest.fixture(scope="class")
def exec_database_sql_class():
    print("前置操作-===数据库查询")
    yield
    print("后置操作=====数据校验")

# 指定要使用的固件
@pytest.mark.usefixtures('exec_database_sql_class')
class TestA:
    def test_a(self):
        print('test_a')

    def test_b(self):
        print('test_b')

会话的前后置

一般会结合conftest.py文件(用于单独存放fixture固件的配置文件)一起使用。

conftest.py

@pytest.fixture(scope="session",autouse=True)
def exec_database_sql():
    print("前置操作-===所有请求前执行一次")
    yield
    print("后置操作=====所有请求之后执行一次")

再使用session.request来做请求

common

yaml_util.py 

yaml_util提供对yaml文件的操作。可以在需要保存全局变量的地方,将变量写入到yaml文件中

import os

import yaml


# 读yaml文件
def read_yaml(key):
    with open(os.getcwd() + '/extract.yml', encoding='utf-8') as f:
        yaml_content = yaml.load(stream=f, Loader=yaml.FullLoader)
        return yaml_content[key]


# 写yaml文件,mode='a'表示追加的方式更新
def write_yaml(data):
    with open(os.getcwd() + '/extract.yml', encoding='utf-8', mode='a') as f:
        yaml.dump(data, stream=f, allow_unicode=True)


# 清空yaml文件,mode='w'表示覆盖的方式更新、清空
def clear_yaml():
    with open(os.getcwd() + '/extract.yml', encoding='utf-8', mode='w') as f:
        f.truncate()
conftest.py

from common.yaml_util import clear_yaml


@pytest.fixture(scope="session",autouse=True)
def exec_database_sql():
    # 每次请求前清空yaml变量文件
    clear_yaml()
    print("前置操作-===所有请求前执行一次")
    yield
    print("后置操作=====所有请求之后执行一次")

allure测试报告

  • 官网下载:https://github.com/allure-framework/allure2/releases
  • 安装目录/bin配置到环境变量path中
  • 查看是否安装成功:allure --version
  • 命令中加入:--alluredir ./temps --clean-aullredir,生成临时的json格式报告到temps的目录下
  • 生成HTML报告:os.system("allure generate ./temp -o ./report --clean");注意如果出现乱码错误,可能是由于pyCharm的环境变量没有配置的原因

一个接口对应多个测试用例

  1. 使用@pytest.mark.parametrize(argnames=,argvalues=),argvalues有多少条值,就有多少个测试用例

 

@pytest.mark.parametrize(argnames='parminfo', argvalues=['啊', '们'])
    def test_01(self, parminfo):
        print(parminfo)

    @pytest.mark.parametrize(argnames='parminfo', argvalues=[['啊', '们'], ['额', '喔']])
    def test_02(self, parminfo):
        print(parminfo)

    @pytest.mark.parametrize(argnames='p1,p2', argvalues=[['啊', '们'], ['额', '喔']])
    def test_03(self, p1, p2):
        print(p1, p2)
  1. 通过yaml来管理接口自动化测试的用例

yaml是一种数据格式,主要用于配置文件或编写用例。yaml中列表用'-'表示

一个py文件可以有多个接口,一般一个接口对应一个yaml文件,yaml文件中有几十个用例,有正例和反例

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值