pytest单元测试(训练篇)-接口自动化:内含不同接口只需登录一次的方法“自动登录”
一、接口文档
1.API文档
2.需求文档
接口测试工具--》接口测试脚本--》接口测试框架
二、 利用fixture自动化就绪测试条件
- 部分接口来说,需要保持登录状态
- 部分接口来说,需要接口关联
- 动态数据
接口信息
- 任务列表 接口地址 GET https://api.tttt.one/rest-v2/todo 参数 无 响应状态码: 200 - 登录: 接口地址 POST https://api.tttt.one/rest-v2/login/access_token 参数 { "password": "bf123456", "email": "bf@qq.com" } 响应状态码 :200 - 创建任务 接口地址 POST https://api.tttt.one/rest-v2/todo { "title": "null", "is_done": False } 响应状态码 :200 - 修改任务 接口地址 PUT https://api.tttt.one/rest-v2/todo/{todo_id} 参数
{ "title": "null", "is_done": False } 响应状态码 :200 - 删除任务 接口地址 https://api.tttt.one/rest-v2/todo/{todo_id} 参数 无 响应状态码 :204
任务列表
HTTP状态码 401 代表的意思:未登录身份凭据(未登录)
获取登录token,传入登录token。但是测试多个接口时,会需要多次的登录,比如下面(代码不是很好,只供比较),就用到两个token,即登录了2次(所以需要“自动登录”,即下一节讲的)
import pytest import requests @pytest.fixture def user_token(): data = { "password": "bf123456", "email": "bf@qq.com" } resp = requests.post("https://api.tttt.one/rest-v2/login/access_token", json=data) assert resp.status_code == 200 print(resp.json()) # 打印登录返回的信息 return resp.json()["access_token"] def test_todo_list(user_token): """测试任务列表接口""" resp = requests.get("https://api.tttt.one/rest-v2/todo", headers={"Authorization": "Bearer " + user_token}, # 请求接口的时候传递token。Bearer传递的类型 ) assert resp.status_code == 200 def test_new_list(user_token): """测试创建任务列表接口""" resp = requests.post("https://api.tttt.one/rest-v2/todo", json={ "title": "我的todo标题", "is_done": False }, headers={"Authorization": "Bearer " + user_token}, # 请求接口的时候传递token ) assert resp.status_code == 200
--------------------------------------------------------------------------------
1. 自动登录(整个session只需登录一次)
1. 获取token
2. 使用token
1. 传递
请求头 Authorization
2. 保存
当我们使用 user_session 我们认为它已经是登录的状态了,不需要再关心怎么登录的问题
@pytest.fixture(scope="session") def session(): return requests.Session()
requests中使用同一个session好处:
1. 复用TCP连接,减少系统开销
2. 持久化请求头
- 在A处修改请求头 fixtures
- 会在B处生效 测试用例
@pytest.fixture(scope="session") def user_session(session): """自动登录""" data = {"password": "bf123456", "email": "bf@qq.com"} resp = session.post( "https://api.tttt.one/rest-v2/login/access_token", json=data, ) # 为session设置请求头 ,一次设置,后面用例全都有效 session.headers["Authorization"] = "Bearer " + resp.json()["access_token"] return session
调用: 任务列表,创建任务
def test_todo_list(user_session):
"""测试任务列表接口""" resp = user_session.get( "https://api.tttt.one/rest-v2/todo", ) assert resp.status_code == 200 def test_new_list(user_session): """测试创建任务列表接口""" resp =user_session.post( "https://api.tttt.one/rest-v2/todo", json={ "title": "我的todo标题", "is_done": False }, )
assert resp.status_code == 200
-------------------------------------------------------------------
问题:
如果某个用例希望是【未登录状态】,怎么办?
@pytest.fixture(scope="function") # 每个用例单独使用 def non_token_session(): return requests.Session() def test_todo_list_need_token(non_token_session): resp = non_token_session.get( "https://api.tttt.one/rest-v2/todo", ) assert resp.status_code == 401
2. 接口关联
全局变量,是一种不好的实践方式
对于 【修改 todo】的测试用例来说,它前提条件是什么?
- 已经存在todo
- 用户已经登录
- todo 是由此用户创建的
实现方法: 使用 某用户的账号,创建一个todo
创建 todo 的fixtures:
- 要不要有返回值?
- 如果要有的话,应是什么
todo_id
cookies
修改任务的测试用例
@pytest.fixture # 每个用例单独使用 def todo_id(user_session): data = { "title": "大家好,我是新的todo", "is_done": False } resp = user_session.post("https://api.tttt.one/rest-v2/todo", json=data) assert resp.status_code == 200 return resp.json()['id'] # 返回新创建的todo的id def test_change_list(user_session, todo_id): """测试修改任务列表接口""" """需要todo_id来构建完整接口URL""" """使用了专门为此用例创建的todo""" resp = user_session.put( f"https://api.tttt.one/rest-v2/todo/{todo_id}", # python3.8以上的版本,在url前加 f json={ "title": "我的todo标题", "is_done": False }, ) assert resp.status_code == 200
完整的全部用例如下:
import pytest import requests @pytest.fixture(scope="session") def session(): return requests.Session() @pytest.fixture(scope="function") # 每个用例单独使用 def non_token_session(): return requests.Session() @pytest.fixture(scope="session") def user_session(session): """自动登录""" data = {"password": "bf123456", "email": "bf@qq.com"} resp = session.post( "https://api.tttt.one/rest-v2/login/access_token", json=data, ) # 为session设置请求头 ,一次设置,后面用例全都有效 session.headers["Authorization"] = "Bearer " + resp.json()["access_token"] return session @pytest.fixture # 每个用例单独使用 def todo_id(user_session): data = { "title": "大家好,我是新的todo", "is_done": False } resp = user_session.post("https://api.tttt.one/rest-v2/todo", json=data) assert resp.status_code == 200 return resp.json()['id'] # 返回新创建的todo的id def test_todo_list_need_token(non_token_session): resp = non_token_session.get( "https://api.tttt.one/rest-v2/todo", ) assert resp.status_code == 401 def test_todo_list(user_session): """测试任务列表接口""" resp = user_session.get( "https://api.tttt.one/rest-v2/todo", ) assert resp.status_code == 200 def test_new_list(user_session): """测试创建任务列表接口""" resp = user_session.post( "https://api.tttt.one/rest-v2/todo", json={ "title": "修改后的标题", "is_done": False }, ) assert resp.status_code == 200 def test_change_list(user_session, todo_id): """测试修改任务列表接口""" """需要todo_id来构建完整接口URL""" """使用了专门为此用例创建的todo""" resp = user_session.put( f"https://api.tttt.one/rest-v2/todo/{todo_id}", # python3.8以上的版本,在url前加 f json={ "title": "我的todo标题", "is_done": False }, ) assert resp.status_code == 200 def test_delete_todo(user_session, todo_id): """ 测试 删除任务 接口 使用为此用例,准吗创建的todo :param user_session: :param todo_id: :return: """ pass
3. 动态数据
4. 数据驱动测试
外部数据,放在什么地方:
excel、 csv 、db、 yaml 、xml、 json
以上区别是: 需要使用不同库,来加载数据
共同点:加载到python之后,数据类型是一样:
列表、字典、字符串、整数
举例:excel作为数据存储
用python 读写execl : openpyxl 支持Excel 2016 以后的版本 .xlsx
pip install openpyxl
总结. 接口测试框架中做了什么
1. 解决登录问题
2. 解决数据驱动问题 通过参数,加载不同的数据
3. 记录接口响应数据
4. 支持更多的外部数据
5. 接口Mock
6. 接口切换测试环境
封装成一个接口测试框架
团队成员,不需要写代码,也可以进行自动化测试
可以自动越苏和提示,避免他们出错