接口测试封装思想
配置:
根据配置文件获取初始配置和依赖
接口封装:
封装接口调用进行抽象封装
类似PageObject效果
业务流程:
数据初始化
业务用例设计,含有多个api形成的流程定义,不要再包含任何接口实现细节。
断言
测试框架
API对象:完成对接口的封装
接口测试框架:完成对api的驱动
配置模块:完成配置文件的读取
数据封装:数据构造与测试用例的数据封装
Utils:其他功能封装,改进原生框架不足
测试用例:调用API对象实现业务并断言
框架实现
选择语言(尽量使用与研发一致的编程语言和技术栈)
Python
Java kotlin
go
选择合适的测试框架
java + RestAssured + JUnit4/JUnit5/TestNG + Allure2
Python + Requests + PyTest + Allure2 = HttpRunner
API对象
架构设计
多协议支持,http tcp thrift等,需要不同的底层引擎
保证用例的协议无关,基于接口或者抽象实现
实现
code方式:输出=业务.功能(输入)
配置文件方式:yaml格式、json格式
多环境支持
联调环境
测试环境
预发环境
线上环境
架构管理
使用package管理业务模块
使用class管理业务功能
使用method完成业务具体行为
使用配置文件读取初始配置
使用继承规划用例执行顺序
使用testcase完成测试用例的落地
使用assertion完成业务正确性校验
使用数据文件管理用例的数据驱动
使用jenkins完成持续集成
基于加密接口测试用例设计
处理加密接口思想
1、对响应加密的接口,对它发起一个get请求后,得到一个加密过后的响应信息。(如果有可用的加密过的接口以及了解他的解密方法,可以跳过)
2、准备一个加密文件
3、使用python命令在有加密文件的所有在目录启动一个服务
4、访问该网站
操作流程
新建一个json文件 demo.json
vim demo.json
“ID”:1
“name”:“xiaoming”
“age”:18
使用base64 生成加密文件
base64 demo.json > demo2.txt
创建一个文件夹,并且将加密后的文件剪切到文件夹下
mkdir demo
mv demo2.txt demo
切入到创建的文件夹下,使用python启动服务
python3 -m http.server 9999
使用浏览器访问,查看加密文件
http://127.0.0.1:9999
原理
在得到响应后对响应做解密处理
1、如果知道使用的是哪个通用加密算法的话,可以自行解决。
2、如果不了解对应的加密算法的话,可以让研发提供加密的lib。
3、如果既不是通用加密算法、研发也无法提供加解密的lib的话,可以让加密方提供远程解析服务,这样算法任然的是保密的。
import base64
import json
import requests
def test_encode():
url = 'http://127.0.0.1:9999/demo2.txt'
r = requests.get(url=url)
res = json.loads(base64.b64decode(r.content))
return res
多环境下的接口测试
实现原理
在请求之前,对请求的url进行替换:
1、需要二次封装requests,对请求进行定制化
2、将请求的结构体的url从一个写死的ip地址改为一个(任意)域名。
3、使用env配置文件,存放各个环境的配置信息
4、然后将请求结构体中的url替换为’env’配置文件中个人选择的url
5、将env配置文件使用yaml进行管理
基础替换
import requests
class API:
data = {
"method": "get",
"url": "https://www.baidu.com/",
"headers": None
}
def env(self):
data_url = str(self.data["url"]).replace('www.baidu.com', '127.0.0.1') # 使用字符串替换完成URL替换
r = requests.request(method=self.data["method"], url=data_url, headers=self.data["headers"])
return r.json()
通过读取yaml文件,来改变环境的地址
env.yaml文件
"default": "pre"
"env_data":
"pre": "www.baidu.com"
"test": "www.baidu.com2"
"dev": "www.baidu.com"
封装发送请求逻辑env.py
import requests
import yaml
class API():
# env_data = {
# "default": "pre",
# "env_data": {
# "pre": "www.baidu.com",
# "test": "www.baidu.com2",
# "dev": "www.baidu.com"}
# }
env_data = yaml.safe_load(open('env.yaml'))
print(env_data)
def env(self,data:dict):
data_url = str(data["url"]).replace('127.0.0.1', self.env_data["env_data"][self.env_data["default"]])
r = requests.request(method=data["method"], url=data_url, headers=data["headers"])
return r
调用env逻辑test_demo.py
from demo1.env import API
class TestAPI():
data = {
"method": "get",
"url": "https://127.0.0.1/",
"headers": None
}
def test_evn(self):
r = API().env(self.data)
print(r.json)
API Object原则
传统case问题
高耦合性、可维护性差
API Object模式
思想与PageObject相通
隔离变与不变的内容
接口细节和业务进行抽离
API Object原则
每一个公共方法代表接口所有提供功能
不要暴露api内部细节
不要在接口实现层些断言
每一个method返回其他的api object或者用来做断言的信息
不需要每个api都进行实现
通过代码实现用例运行,运行用例后返回对应的返回信息,使用外部的文档来编辑用例,并且做对应的断言
API基础封装
实现原理
1、把发起的请求信息转化为一个字典结构体
2、直接使用python关键字传参的方式,将请求结构体传给requests.request方法
基础封装小样
baseApi.py
import requests
class BaseApi:
def http_request(self,data):
res = requests.request(**data)
return res.json
test_case.py
from demo2.api.baseApi import BaseApi
class TestCase(BaseApi):
data = {
"method": "get",
"url": "https://www.baidu.com/",
"headers": None
}
def test_case(self):
r = BaseApi().http_request(self.data)
print(r)