4.测试案例实现代码库与测试用例V2.0
测试案例实现代码库与测试用例V2.0
接口分析
- 1、接口认证机制--cookies
- 存储在请求头中
- 2、接口风格---restful
- 数据格式为json
- 请求方法
- 查询:GET
- 增加:POST
- 修改:PUT
- 删除:DELETE
面临的问题
- 接口众多如何快速开发?
- API之前相同,且有规律
APIObject设计模式
- rest风格的接口特点
- 增加--POST
- 修改--PUT
- 删除--DELETE
- 查询--GET
按照面向对象的思路,把接口进行重新设计一遍
- BaseAPI的设计
- 统一增删改查API
- 接口参数模板化
- 接口数据与测试脚本分离
在common中新增一个类
class BaseAPI:
path="???"
payload="???"
#增加
def add(self):
pass
#修改
def edit(self):
pass
#删除
def delete(self):
pass
#查询
def list_all(self):
pass
#删除所有
def delete_all(self):
pass
但是path和payload怎么处理,每个接口都不一样,新增一个配置文件,通过读取配置文件来获取
配置文件
api_conf.yml
OrganizAPI:
path: /api/v4/organizations
add:
{
"name": "utuytut",
"parent": "qpG8DsWSaY8FAwWxN",
"sort_no": 100,
"hidden": false,
"space": "NhnKCEchFReJbgqZM"
}
edit:
{
"name": "testccc",
"parent": "qpG8DsWSaY8FAwWxN",
"sort_no": 100,
"hidden": false,
"space": "NhnKCEchFReJbgqZM"
}
修改的请求体不一样,多了一层$set
{
"$set": {
"name": "testccc",
"parent": "qpG8DsWSaY8FAwWxN",
"sort_no": 100,
"hidden": false,
"space": "NhnKCEchFReJbgqZM"
}
}
配置文件,只放set对应的value,跟上面的add保持一致,后面传参的时候再把$set加进去
现在配置文件有了,那我们需要把它读取出来
读取配置文件
在pylib下面配置一个通用的文件夹,utils,再在此文件夹下面新增一个config.py文件
然后定义一个读取yml文件的方法:def read_yml(path):
import yaml
def read_yml(path):
with open(path,encoding='utf-8') as f :
content=f.read()
data=yaml.safe_load(content)
return data
测试下能不能正常读取到内容
if __name__ == '__main__':
print(read_yml('../../conf/api_conf.yml'))
输出:
{'OrganizAPI': {'path': '/api/v4/organizations', 'add': {'name': 'utuytut', 'parent': 'qpG8DsWSaY8FAwWxN', 'sort_no': 100, 'hidden': False, 'space': 'NhnKCEchFReJbgqZM'}, 'edit': {'name': 'testccc', 'parent': 'qpG8DsWSaY8FAwWxN', 'sort_no': 100, 'hidden': False, 'space': 'NhnKCEchFReJbgqZM'}}}
分析发现每个接口的增删改查接口的path都是一样,那么只需要在实例化的时候读取出来就可以了
- 注意,以后测试用例都是从根目录开始,现在需要变换相对路径,要从项目根目录开始
BaseAPI
class BaseAPI:
def __init__(self):
self.api_conf=read_yml('conf/api_conf.yml')['OrganizAPI']
写死OrganizAPI,这样有一个问题,目前只能读取到OrganizAPI,如果是其他api就读取不到数据
观察发现,刚才读取的数据,这个key跟类名相同
如何取当前类名
def __init__(self):
currrent_name=self.__class__.__name__
self.api_conf=read_yml('conf/api_conf.yml')[currrent_name]
可以在business里面初始化一个OrganizAPI,ContractsAPI分别测试下获取的类名是否正确
接下来直接实现baseapi的增删改查
def add(self,name='lily',age=11):
不确定入参是多少个的时候,且入参是关键字参数,可与采用字典形式传参
def add(self,**kwargs):
下面是要处理哪些数据是动态替换的,哪些数据是可以写死的
space从登录返回的cookie里面获取cookies['X-Space-Id']
<RequestsCookieJar[<Cookie X-Access-Token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InRva2VuIjoiMTdjOGE0NjVkNDRlNGUzNzBmNTE5OWUzNmYxNjFhN2NiN2I1NDI4MTQ4MDNiOWYwNzg4YTk2MDY4ZDg0YmIwOGI2ZDFkODgyMzMzZjg4ODY2OTA1MDgiLCJpc0ltcGVyc29uYXRlZCI6ZmFsc2UsInVzZXJJZCI6IjVmZDg3NDM0YjQyODAzMDAxMmYyNjFiZiJ9LCJpYXQiOjE2Mjc4MjI3ODYsImV4cCI6MTYzNTU5ODc4Nn0.NYJ-z5iA30i5Vd3xq4QnJ3X1a-pzUUmgEnRlguXRHSQ for 120.27.146.185/>, <Cookie X-Auth-Token=17c8a465d44e4e370f5199e36f161a7cb7b542814803b9f0788a96068d84bb08b6d1d882333f8886690508 for 120.27.146.185/>, <Cookie X-Space-Id=tY4wsv85gTFhk6B5N for 120.27.146.185/>, <Cookie X-Space-Token=tY4wsv85gTFhk6B5N,17c8a465d44e4e370f5199e36f161a7cb7b542814803b9f0788a96068d84bb08b6d1d882333f8886690508 for 120.27.146.185/>, <Cookie X-User-Id=5fd87434b428030012f261bf for 120.27.146.185/>]>
tY4wsv85gTFhk6B5N
class BaseAPI:
def __init__(self,cookies):
currrent_name=self.__class__.__name__
self.api_conf=read_yml('conf/api_conf.yml')[currrent_name]
self.path=self.api_conf['path']
self.cookies=cookies
self.space =cookies['X-Space-Id']#跟随管理员用户
#增加
def add(self,**kwargs):
url=f'{host}{self.path}'
payload=self.api_conf['add']#通过模板取数据
payload.update(kwargs)#处理动态替换数据,dict = {'Name': 'Zara', 'Age': 7},dict2 = {'Sex': 'female' },dict.update(dict2)
payload['space']=self.space
res =requests.post(url,json=payload,cookies=self.cookies)
return res.json()['value'][0]#返回数据在value的唯一一个元素中
完整代码
class BaseAPI:
def __init__(self,cookies):
#取当前类名
current_name=self.__class__.__name__
#通过类名获取api的配置信息
self.api_conf=read_yml('conf/api_conf.yml')[current_name]
self.path=self.api_conf['path']#获取URL的path
self.cookies=cookies#初始化的时候传递cookies信息
self.space =cookies['X-Space-Id']#跟随管理员用户,空间ID
#增加
def add(self,**kwargs):
url=f'{host}{self.path}'
payload=self.api_conf['add']#通过模板取数据
payload.update(kwargs)#处理动态替换数据,dict = {'Name': 'Zara', 'Age': 7},dict2 = {'Sex': 'female' },dict.update(dict2)
payload['space']=self.space
res =requests.post(url,json=payload,cookies=self.cookies)
return res.json()['value'][0]#所有新增接口返回数据在value的唯一一个元素中
#修改
def edit(self,_id,**kwargs):
url=f'{host}{self.path}/{_id}'
payload=self.api_conf['edit']
payload.update(kwargs)
payload['space']=self.space
data={}
data['$set'] =payload
res =requests.put(url,json=data,cookies=self.cookies)
#删除
def delete(self,_id):
url =f'{host}{self.path}/{_id}'
res =requests.delete(url,cookies=self.cookies)
return res.json()
#查询所有
def list_all(self):
url=f'{host}{self.path}'
res =requests.get(url,cookies=self.cookies)
return res.json()['value']
#删除所有
def delete_all(self):
lists=self.list_all()
for list in lists:
self.delete(list['_id'])