接口对象封装
1.requests和pymysql实现ihrm登录接口缺点 : 代码冗余度高,耦合度高,维护成本大
核心思想 : 代码分层
- 按代码功能划分 :
- 接口对象层 : 负责发送http请求,访问待测接口,返回响应数据
- 测试用例层 : 调用接口,按照响应数据,断言完成测试
封装tpshop商城
- 普通方式实现
python
# 导包----我的tpshop有问题,故省略url
import requests
# 创建session对象
session=requests.Session()
# 发送验证码请求get
session.get(url="")
# 发送登录请求 post
resp=session.post(url="",date={"username":"12345678","password":"123456","varify":"8888"})
# 打印响应结果
print("登录结果:",resp.json())
登录接口对象层
- 封装思想 :
- 将普通方式实现代码中固定不变的,直接写到方法的实现内部
- 将动态变化的,从参数传入
- 将响应结果,通过返回值return
- 示例分析:
python
import requests
# 封装tpshop商城,接口对象层
class TpshopLoginApi(object):
@classmethod
# 获取验证码---普通实现固定不变
def get_verify(cls,session):
session.get(url="http://tpshop-test.itcast.itheima.net/index.php?m=Home&c=User&a=verify")
# 登录
@classmethod
def login(cls,session,login_data):
resp=session.post(url="http://tpshop-test.itcast.itheima.net/index.php?m=Home&c=User&a=verify",
date=login_data)
# 返回值
return resp
# 验证:测试自己封装的接口,功能是否正常
if __name__=='__main__':
session=requests.Session()
# 发送获取验证码请求
TpshopLoginApi.get_verify(session)
login_data={"username":"12345678","password":"123456","varify":"8888"}
# 发送登录请求
response=TpshopLoginApi.login(session,login_data)
print("登录结果:",response.json())
具体实现:
1.将普通实现代码中,固定不变的和动态变换的,不变的写到参数内部,动态的通过参数传过去
2.有返回值通过return做返回
3.写测试的代码进行测试
登录接口测试用例层
- 使用pytest框架,调用自己封装的Api发送请求,获取响应结果,断言,完成接口测试!
- 优化前
python
import requests
from py_tpshopFZ import TpshopLoginApi
class TestTpshopLogin(object):
# 定义测试方法 - 登录成功
def test01_login_success(self):
# 创建session实例
session=requests.Session()
# 调用自己封装的api,发送获取验证码请求
TpshopLoginApi.get_verify(session)
# 准备请求体数据
req_data={"username":"12345678","password":"123456","verify":"8888"}
# 调用自己封装的API,发送登录请求
resp=TpshopLoginApi.login(self,req_data)
# 打印响应结果:
print("登录成功:",resp.json())
# 断言
assert 200 == resp.status_code()
assert 1 == resp.json().get("status")
assert "登陆成功" in resp.json().get("msg")
# 定义测试方法 - 密码错误
def test02_pwd_err(self):
# 创建session实例
session = requests.Session()
# 调用自己封装的api,发送获取验证码请求
TpshopLoginApi.get_verify(session)
# 准备请求体数据
req_data = {"username": "12345678", "password": "1234561212", "verify": "8888"}
# 调用自己封装的API,发送登录请求
resp = TpshopLoginApi.login(self, req_data)
# 打印响应结果:
print("密码错误:", resp.json())
# 断言
assert 200 == resp.status_code()
assert -2 == resp.json().get("status")
assert "密码错误" in resp.json().get("msg")
# 定义测试方法 - 验证码错误
def test03_verify_err(self):
# 创建session实例
session = requests.Session()
# 调用自己封装的api,发送获取验证码请求
TpshopLoginApi.get_verify(session)
# 准备请求体数据
req_data = {"username": "12345678", "password": "123456", "verify": "9999"}
# 调用自己封装的API,发送登录请求
resp = TpshopLoginApi.login(self, req_data)
# 打印响应结果:
print("验证码错误:", resp.json())
# 断言
assert 200 == resp.status_code()
assert 0 == resp.json().get("status")
assert "验证码错误" in resp.json().get("msg")
- 优化后
py
import requests
from py_tpshopFZ import TpshopLoginApi
class TestTpshopLogin(object):
# 定义为类属性,使用时类属性可以用类名,实例,self,cls均可引用
session = None
# 每个方法调用前都执行一次
def setup(self):
# 创建session实例
self.session=requests.Session()
# 调用自己封装的API,发送获取验证码请求---索引类属性语法规范
TpshopLoginApi.get_verify(self.session)
# 定义测试方法 - 登录成功
def test01_login_success(self):
# 准备请求体数据
req_data={"username":"12345678","password":"123456","verify":"8888"}
# 调用自己封装的API,发送登录请求
resp=TpshopLoginApi.login(self.session,req_data)
# 打印响应结果:
print("登录成功:",resp.json())
# 断言
assert 200 == resp.status_code()
assert 1 == resp.json().get("status")
assert "登陆成功" in resp.json().get("msg")
# 定义测试方法 - 密码错误
def test02_pwd_err(self):
# 准备请求体数据
req_data = {"username": "12345678", "password": "1234561212", "verify": "8888"}
# 调用自己封装的API,发送登录请求
resp = TpshopLoginApi.login(self.session, req_data)
# 打印响应结果:
print("密码错误:", resp.json())
# 断言
assert 200 == resp.status_code()
assert -2 == resp.json().get("status")
assert "密码错误" in resp.json().get("msg")
# 定义测试方法 - 验证码错误
def test03_verify_err(self):
# 创建session实例
session = requests.Session()
# 调用自己封装的api,发送获取验证码请求
TpshopLoginApi.get_verify(session)
# 准备请求体数据
req_data = {"username": "12345678", "password": "123456", "verify": "9999"}
# 调用自己封装的API,发送登录请求
resp = TpshopLoginApi.login(self.session, req_data)
# 打印响应结果:
print("验证码错误:", resp.json())
# 断言
assert 200 == resp.status_code()
assert 0 == resp.json().get("status")
assert "验证码错误" in resp.json().get("msg")
搭建自动基础化框架
- 名称apiTestFramework(package存放带码,dict存放测试报告)
- api : 定义封装被测系统的接口
- scripts : 定义测试用例脚本
- data : 存放测试数据文件
- report : 存放生成的测试报告
- common : 存放通用工具类
- config.py : 定义项目的配置信息
- run_suite.py : 执行测试套件的入口
封装ihrm登录
- 准备数据--->调接口--->得响应结果---->设断言
- 普通实现
python
import requests
resp=requests.post(url="https://ihrm-java.itheima.net/api/sys/login",
headers={"Content-Type":"application/json"},
json={"mobile": "13800000002","password": "[email protected]"})
print("打印结果:",resp.json())
- 登录接口用例层---------登录接口封装
python
import requests
# 定义ihrm登录接口 类
class IhrmloginApi(object):
# 定义方法
@classmethod
def login(cls,rep_data):
resp=requests.post(url="https://ihrm-java.itheima.net/api/sys/login",json=rep_data)
return resp
# 测试接口封装是否成功
if __name__=='__main__':
data={"mobile": "13800000002","password": "[email protected]"}
# 传参进行调用
resp=IhrmloginApi.login(data)
print("登录成功:",resp.json())
- 登录接口测试用例层
python
from api.ihrm_loginapi import IhrmloginApi
class TestIhrmLogin(object):
# 定义测试方法--登录成功
def test_01_login_success(self):
# 准备登录测试数据
data = {"mobile": "13800000002","password": "[email protected]"}
# 调用自己封装的api 获取响应结果
resp=IhrmloginApi.login(data)
# 打印查看
print("登陆成功:",resp.json())
# 断言
assert 200 == resp.status_code
assert True == resp.json().get('success')
assert 10000 == resp.json().get("code")
assert '操作成功' in resp.json().get('message')
# 定义测试方法--手机号未注册
def test_02_mpbile(self):
# 准备登录测试数据
data = {"mobile": "13800000001", "password": "[email protected]"}
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(data)
# 打印查看
print("手机号未注册:", resp.json())
# 断言
assert 200 == resp.status_code
assert False == resp.json().get('success')
assert 20001 == resp.json().get("code")
assert '用户名或密码错误' in resp.json().get('message')
# 定义测试方法--手机号未注册
def test_02_pwd_err(self):
# 准备登录测试数据
data = {"mobile": "13800000002", "password": "[email protected]"}
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(data)
# 打印查看
print("密码错误:", resp.json())
# 断言
assert 200 == resp.status_code
assert False == resp.json().get('success')
assert 20001 == resp.json().get("code")
assert '用户名或密码错误' in resp.json().get('message')
- 封装断言方法:
- 在项目目录下, 创建common目录,添加文件assert_tools.py
- 在文件assert_tools.py添加通用的断言函数common_assert()
- 实现此函数
- 在测试脚本层,需要断言的位置,使用这个断言函数来实现
python
"""定义通用的工具函数 实现断言"""
# 谁调用就给一个resp
def common_assert(resp,status_code,success,code,message):
assert status_code == resp.status_code
assert success is resp.json().get("success")
assert code == resp.json().get("code")
assert message in resp.json().get("message")
- 加入断言优化后
python
from api.ihrm_loginapi import IhrmloginApi
from common.assert_tools import common_assert
class TestIhrmLogin(object):
# 定义测试方法--登录成功
def test_01_login_success(self):
# 准备登录测试数据
data = {"mobile": "13800000002","password": "[email protected]"}
# 调用自己封装的api 获取响应结果
resp=IhrmloginApi.login(data)
# 打印查看
print("登陆成功:",resp.json())
# 断言
common_assert(resp, 200, True, 10000, "操作成功")
# 定义测试方法--手机号未注册
def test_02_mobile(self):
# 准备登录测试数据
data = {"mobile": "13800000001", "password": "[email protected]"}
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(data)
# 打印查看
print("手机号未注册:", resp.json())
# 断言
common_assert(resp, 200, False, 20001, "用户名或密码错误")
# 定义测试方法--密码错误
def test_03_pwd_err(self):
# 准备登录测试数据
data = {"mobile": "13800000002", "password": "[email protected]"}
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(data)
# 打印查看
print("密码错误:", resp.json())
# 断言
common_assert(resp, 200, False, 20001, "用户名或密码错误")
# 电话号码为空
def test_04_mobile_is_none(self):
# 准备登录测试数据
data = {"mobile": "", "password": "[email protected]"}
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(data)
# 打印查看
print("手机号为空:", resp.json())
# 断言
common_assert(resp, 200, False, 20001, "用户名或密码错误")
# 电话有特殊字符
def test_05_mobile_have_special_char(self):
# 准备登录测试数据
data = {"mobile": "1213#######", "password": "[email protected]"}
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(data)
# 打印查看
print("手机号有特殊字符:", resp.json())
# 断言
common_assert(resp, 200, False, 20001, "用户名或密码错误")
# 10位电话号码
def test_06_mobile10(self):
# 准备登录测试数据
data = {"mobile": "", "password": "[email protected]"}
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(data)
# 打印查看
print("10位手机号", resp.json())
# 断言
common_assert(resp, 200, False, 20001, "用户名或密码错误")
# 12位电话号码
def test_07_mobile12(self):
# 准备登录测试数据
data = {"mobile": "111111111111", "password": "[email protected]"}
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(data)
# 打印查看
print("12位手机号:", resp.json())
# 断言
common_assert(resp, 200, False, 20001, "用户名或密码错误")
# 密码为空
def test_08_pwd_empty(self):
# 准备登录测试数据
data = {"mobile": "13800000002", "password": None}
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(data)
# 打印查看
print("12位手机号:", resp.json())
# 断言
common_assert(resp, 200, False, 20001, "用户名或密码错误")
# 密码有特殊字符
def test_09_pwd_have_special_char(self):
# 准备登录测试数据
data = {"mobile": "13800000002", "password": "929@@@@@"}
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(data)
# 打印查看
print("密码有特殊字符:", resp.json())
# 断言
common_assert(resp, 200, False, 20001, "用户名或密码错误")
# 密码1位
def test_10_pwd01(self):
def test_09_pwd_have_special_char(self):
# 准备登录测试数据
data = {"mobile": "13800000002", "password": "9"}
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(data)
# 打印查看
print("密码1位:", resp.json())
# 断言
common_assert(resp, 200, False, 20001, "用户名或密码错误")
# 密码100位
def test_11_pwd100(self):
def test_09_pwd_have_special_char(self):
# 准备登录测试数据
data = {"mobile": "13800000002",
"password": "929@@@@@@@929@@@@@@@929@@@@@@@929@@@@@@@929@@@@@@@929@@@@@@@929@@@@@@@929@@@@@@@929@@@@@@@"}
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(data)
# 打印查看
print("100位密码:", resp.json())
# 断言
common_assert(resp, 200, False, 20001, "用户名或密码错误")
# 多参数
def test_12_more_params(self):
# 准备登录测试数据
data = {"mobile": "13800000002", "password": "[email protected]","ara":"demo"}
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(data)
# 打印查看
print("登陆成功:", resp.json())
# 断言
common_assert(resp, 200, True, 10000, "操作成功")
# 少参
def test_13_less_params(self):
# 准备登录测试数据
data = {"mobile": "13800000002"}
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(data)
# 打印查看
print("少参password:", resp.json())
# 断言
common_assert(resp, 200, False, 20001, "用户名或密码错误")
# 无参
def test_14_no_params(self):
# 准备登录测试数据
data = None
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(None)
# 打印查看
print("少参password:", resp.json())
# 断言
common_assert(resp, 200, False, 99999, "抱歉")
# 错误参数
def test_15_err_params(self):
# 准备登录测试数据
data = {"abc": "13800000002","password": "[email protected]"}
# 调用自己封装的api 获取响应结果
resp = IhrmloginApi.login(data)
# 打印查看
print("无参:", resp.json())
# 断言
common_assert(resp, 200, False, 20001, "用户名或密码错误")
- data有相似的值,把登录接口参数化写入json文件
json
[
{
"desc": "登录成功",
"req_date":{
"mobile": "13800000002",
"password": "[email protected]"
},
"status_code":200,
"success": true,
"code": 10000,
"message": "操作成功!"
},
{
"desc": "手机号不存在",
"req_date":{
"mobile": "13800000001",
"password": "[email protected]"
},
"status_code":200,
"success": false,
"code": 20001,
"message": "用户名或密码错误"
},
{
"desc":"密码错误",
"req_date":{
"mobile": "13800000002",
"password": "[email protected]"
},
"status_code":200,
"success": false,
"code": 20001,
"message": "用户名或密码错误"
},
{
"desc": "手机号为空",
"req_date":{
"mobile": null,
"password": "[email protected]"
},
"status_code": 200,
"success": false,
"code": 20001,
"message": "用户名或密码错误"
},
{
"desc": "手机号特殊字符",
"req_data": {"mobile": "13@######",
"password": "[email protected]"
},
"status_code": 200,
"success": false,
"code": 20001,
"message": "用户名或密码错误"
},
{
"desc": "10位手机号",
"req_data": {"mobile": "1323333333",
"password": "[email protected]"
},
"status_code": 200,
"success": false,
"code": 20001,
"message": "用户名或密码错误"
},
{
"desc": "12位手机号",
"req_data": {"mobile": "132333333322",
"password": "[email protected]"
},
"status_code": 200,
"success": false,
"code": 20001,
"message": "用户名或密码错误"
},
{
"desc": "密码为空",
"req_data": {"mobile": "1323333333",
"password": null
},
"status_code": 200,
"success": false,
"code": 20001,
"message": "用户名或密码错误"
},
{
"desc": "密码有特殊字符",
"req_data": {"mobile": "13800000002",
"password": "929@@@@@"
},
"status_code": 200,
"success": false,
"code": 20001,
"message": "用户名或密码错误"
},
{
"desc": "密码1位",
"req_data": {"mobile": "13800000002",
"password": "9"
},
"status_code": 200,
"success": false,
"code": 20001,
"message": "用户名或密码错误"
},
{
"desc": "密码100位",
"req_data": {"mobile": "13800000002",
"password": "929@@@@@@@929@@@@@@@929@@@@@@@929@@@@@@@929@@@@@@@929@@@@@@@929@@@@@@@929@@@@@@@929@@@@@@@"
},
"status_code": 200,
"success": false,
"code": 20001,
"message": "用户名或密码错误"
},
{
"desc": "多参",
"req_data": {"mobile": "13800000002",
"password": "[email protected]",
"ara":"demo"
},
"status_code": 200,
"success": false,
"code": 20001,
"message": "用户名或密码错误"
},
{
"desc": "少参",
"req_data": {"mobile": "13800000002"
},
"status_code": 200,
"success": false,
"code": 20001,
"message": "用户名或密码错误"
},
{
"desc": "无参",
"req_data":null,
"status_code": 200,
"success": false,
"code": 20001,
"message": "抱歉"
},
{
"desc": "错误参数",
"req_data": {"mobile": "13800000002",
"pass": "[email protected]"
},
"status_code": 200,
"success": false,
"code": 20001,
"message": "用户名或密码错误"
}
]
参数化
参数化的核心 : 数据驱动(用数据驱动测试用例执行)
- 数据驱动 : 针对一个接口,只写一个测试方法,用一份测试数据文件,管理各个测试用例的测试数据.
- 如登录接口:15条测试用例,只需要一个测试方法,对应一个含有15组数据的json文件,进行测试
回顾PyTest
- 加法函数