微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

pytest单元测试框架

什么是单元测试框架

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

常见的单元测试框架

java:Junit

python: unittest和pytest

单元测试框架主要做什么

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

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

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

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

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

pytest简介

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

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

plugiininstall.txt文件

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

pytest使用的命名规则

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

pytest测试用例的运行方式

  1. 函数模式(if __name__ == '__main__':)
    1. 运行所有:pytest.main()(使用单独的py文件来运行)
    2. 指定模块:pytest.main(['-vs', 'test_print.py'])(使用单独的py文件来运行)
    1. 指定目录:pytest.main(['-vs', './interface_testcase'])(使用单独的py文件来运行)
    2. 通过nodeid指定用例运行:nodeid由模块名,分隔符,类名,方法名,函数名组成。 pytest.main(['-vs', './interface_testcase/test_interface.py::TestInterface::test_01_demo'])(使用单独的py文件来运行)
  1. 命令行模式
    1. 运行所有:pytest
    2. 指定模块:pytest -vs test_print.py
    1. 指定目录:pytest -vs ./interface_testcase
    2. 通过nodeid指定用例运行:pytest -vs ./interface_testcase/test_interface.py::TestInterface::test_01_demo
  1. 通过读取pytest.ini核心配置文件运行
    1. 位置:项目的跟目录下
    2. 编码:必须是ANSI,可以使用notepad++改变编码格式
    1. 作用:改变pytest的认行为
    2. 运行的规则:不管是主函数的模式运行,还是命令行的模式运行,都会去读取这个配置文件
[pytest]
addopts= -vs
test_paths =./pytest01
python_files=test_*.py
python_classes=Testa*
python_functions=test

pytest参数详解

  • -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

弊端:

  1. 敏捷开发时代,接口数量巨大,工具无法做到团队协作和版本控制
  2. 功能写死了,对于一些复杂的接口(自定义加密和签名接口)
  1. 项目里面有多种协议接口:http、webservice、websocket、dubbo
  2. 排错,定位问题
  1. 没有完整的测试报告
  2. 多接口串联,数据库连接,日志监控
  1. 有些公司即要做接口自动化,又要做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信息
  1. get(url, params=None, **kwargs)
    1. 通过params进行传参
  1. post(url, data=None, json=None, **kwargs)
    1. 通过data传参,
      1. 参数是dict类型:请求头的Content-Type:application/x-www-urlencoded,表示通过表单传参,格式a=1&b=2
      2. 参数是str类型:Content-Type:text/plain
    1. 通过json传参,请求头的Content-Type:applicaiton/json,格式{"a":1}
  1. request(method, url, **kwargs):
    1. method:请求方法类型
    2. url:请求地址
    1. kwargs:字典类型的可变参数
      1. params=,表示get方法传参
      2. data=,表示post方法传参
      1. json=,表示json方法传参
      2. headers=,表示请求头
      1. cookies=,表示cookie关联
      2. 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作用的函数重命名")

    • 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测试报告

  1. 官网下载:https://github.com/allure-framework/allure2/releases
  2. 安装目录/bin配置到环境变量path中
  1. 查看是否安装成功:allure --version
  2. 命令中加入:--alluredir ./temps --clean-aullredir,生成临时的json格式报告到temps的目录下
  1. 生成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文件中有几十个用例,有正例和反例

如果对python自动化测试、web自动化、接口自动化、移动端自动化、大型互联网架构技术、面试经验交流等等感兴趣的老铁们,可以关注我。我会在公众号(程序员阿沐)/群里(810119819)不定期的发放免费的资料链接,这些资料都是从各个技术网站搜集、整理出来的,如果你有好的学习资料可以私聊发我,我会注明出处之后分享给大家。欢迎分享,欢迎评论,欢迎转发。需要资料的同学可以关注我获取资料链接

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐