4.测试案例实现代码库与测试用例V2.0

测试案例实现代码库与测试用例V2.0

接口分析

  • 1、接口认证机制--cookies
    • 存储在请求头中
  • 2、接口风格---restful
    • 数据格式为json
    • 请求方法
      • 查询:GET
      • 增加:POST
      • 修改:PUT
      • 删除:DELETE

面临的问题

  • 接口众多如何快速开发?
  • API之前相同,且有规律

APIObject设计模式

  • rest风格的接口特点
    • 增加--POST
    • 修改--PUT
    • 删除--DELETE
    • 查询--GET

按照面向对象的思路,把接口进行重新设计一遍

  • BaseAPI的设计
    • 统一增删改查API
    • 接口参数模板化
    • 接口数据与测试脚本分离

图 48

在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'])
posted @ 2021-08-01 22:03  幸福一家  阅读(208)  评论(0编辑  收藏  举报