接口自动化框架搭建(一)

使用requests库封装接口请求

详细教程请查看官方文档:https://requests.kennethreitz.org//zh_CN/latest/user/quickstart.html#url

入门教程:https://www.cnblogs.com/huaerye/p/9132607.html

参考文档:https://www.cnblogs.com/shapeL/p/9045439.html

第一次修改:将get请求和post请求单独定义,使用过程中根据不同类型的请求直接调用对应的方法;

def send_get(url,data,headers):
    res = requests.get(url=url,json=data,headers=headers).json()
    # return json.dumps(res,sort_keys=True,indent=2)
    return res
def send_post(url,data,headers):
    res = requests.post(url=url,json=data,headers=headers).json()
    return json.dumps(res,sort_keys=True,indent=4)    #indent默认情况下为空,4个空格,sort_keys:按照一定顺序展示数据

def run_main(url,headers,method,data=None):
    res =None
    if method == 'GET':
        res = send_get(url,data,headers)
    else:
        res = send_post(url,data,headers)
    return res

if __name__=='__main__':
    url = 'https://oapi.blingabc.com/cms/user-api/student/homework/v2/homeworklist'
    headers = {
        'token': "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJjb20ueGRmLmJsaW5nIiwiYXVkIjoiY2xpZW50IiwidXNlcmNvZGUiOiI5NTUxNjMxNyIsImV4cCI6MTU3NDMxNzY2NSwiaWF0IjoxNTczNzEyODY1fQ.UjNSQSQpP6umRubppSggYB1W-dkmnfBB5RMNRQUTS9a8IJDmURyPT1bMIWg5nwHL1z7GvvJ-Ch5PKGLEnwOh6g",
        'Content-Type': "application/json",
        }
    # 数据
    data = {"stuNum":"795571161","page":1,"size": 5,"type":0}
    #url = 'https://oapi.t.blingabc.com/bms/admin-api/specialsubject/v1/save-phonics?id=285'
    print(send_post(url,data,headers))

第二次修改:用class进行封装,主函数中创建一个实例run来调用类中的方法

import requests
import json

class Runmain():
    def send_get(self,url,data,headers):
        res = requests.get(url=url,json=data,headers=headers).json()
        # return json.dumps(res,sort_keys=True,indent=2)
        return res
    def send_post(self,url,data,headers):
        res = requests.post(url=url,json=data,headers=headers).json()
        return json.dumps(res,sort_keys=True,indent=4)    #indent默认情况下为空,4个空格,sort_keys:按照一定顺序展示数据

    def run_main(self,url,headers,method,data=None):
        res =None
        if method == 'GET':
            res = self.send_get(url,data,headers)
        else:
            res = self.send_post(url,data,headers)
        return res

if __name__=='__main__':
    run = Runmain
    url = 'https://oapi.blingabc.com/cms/user-api/student/homework/v2/homeworklist'
    headers = {
        'token': "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJjb20ueGRmLmJsaW5nIiwiYXVkIjoiY2xpZW50IiwidXNlcmNvZGUiOiI5NTUxNjMxNyIsImV4cCI6MTU3NDMxNzY2NSwiaWF0IjoxNTczNzEyODY1fQ.UjNSQSQpP6umRubppSggYB1W-dkmnfBB5RMNRQUTS9a8IJDmURyPT1bMIWg5nwHL1z7GvvJ-Ch5PKGLEnwOh6g",
        'Content-Type': "application/json",
        }
    # 数据
    data = {"stuNum":"795571161","page":1,"size": 5,"type":0}
    #url = 'https://oapi.t.blingabc.com/bms/admin-api/specialsubject/v1/save-phonics?id=285'
    print(run.run_main(url,data,headers))

第三次修改:第二次修改,每次都需要实例化后再调用对应的方法;

改进办法:使用__init__方法实现:只要实例化类时候就会调用__init__方法

import requests
import json

class Runmain():
    def __init__(self,url,headers,method,data=None):
        self.res = self.run_main(url,headers,method,data)
    def send_get(self,url,data,headers):
        res = requests.get(url=url,json=data,headers=headers).json()
        # return json.dumps(res,sort_keys=True,indent=2)
        return res
    def send_post(self,url,data,headers):
        res = requests.post(url=url,json=data,headers=headers).json()
        return json.dumps(res,sort_keys=True,indent=4)    #indent默认情况下为空,4个空格,sort_keys:按照一定顺序展示数据

    def run_main(self,url,headers,method,data=None):
        res =None
        if method == 'GET':
            res = self.send_get(url,data,headers)
        else:
            res = self.send_post(url,data,headers)
        return res

if __name__=='__main__':

    url = 'https://oapi.blingabc.com/cms/user-api/student/homework/v2/homeworklist'
    headers = {
        'token': "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJjb20ueGRmLmJsaW5nIiwiYXVkIjoiY2xpZW50IiwidXNlcmNvZGUiOiI5NTUxNjMxNyIsImV4cCI6MTU3NDMxNzY2NSwiaWF0IjoxNTczNzEyODY1fQ.UjNSQSQpP6umRubppSggYB1W-dkmnfBB5RMNRQUTS9a8IJDmURyPT1bMIWg5nwHL1z7GvvJ-Ch5PKGLEnwOh6g",
        'Content-Type': "application/json",
        }
    # 数据
    data = {"stuNum":"795571161","page":1,"size": 5,"type":0}
    #url = 'https://oapi.t.blingabc.com/bms/admin-api/specialsubject/v1/save-phonics?id=285'
    run = Runmain(url,headers,data,'post')
    print(run.res)

最后修改后的文件:将形参写到构造方法中,params=None,data=None,需要时可以传入参数;

demo.py使用requests get以及post方法进行了封装,主要是根据传递的参数method来对get以及post方法进行分别调用

import requests
import json

class Runmain():
    def __init__(self,url,headers,method,params=None,data=None):
        self._url=url
        self._params = params
        self._data = data
        self._headers = headers
        self._method = method

    def send_get(self,url,params,headers):
        res = requests.get(url=url,params=params,headers=headers).json()
        #return json.dumps(res,sort_keys=True,indent=2)
        return res
    def send_post(self,url,data,headers):
        res = requests.post(url=url,json=data,headers=headers).json()
        return json.dumps(res,sort_keys=True,indent=4)

    def run_main(self):
        if self._method == 'GET':
            return self.send_get(self._url,self._params,self._headers)
        else:
            return self.send_post(self._url,self._data,self._headers)

if __name__=='__main__':

    url = 'https://oapi.t.blingabc.com/bms/admin-api/studentPreview/v1/myPreviews'
    headers = {
        'token': "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJjb20ueGRmLmJsaW5nIiwiYXVkIjoiY2xpZW50IiwidXNlcmNvZGUiOiI5NTUxNjMxNyIsImV4cCI6MTU3NDMzMDY5NiwiaWF0IjoxNTczNzI1ODk2fQ.yWaCaeOzZfVGokA7D7wrGeItcKPeyuythWIU52_1-rqZ9vEpYWRl6EYmq5thebccD0SecVpu6qLZm3NZu9DIqQ",
        'Content-Type': "application/json",
        #'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36"
        }
    # 数据
    data = {"stuNum":"955163171","page":1,"size":5,"type":2}
    # url = 'https://oapi.t.blingabc.com/bms/admin-api/specialsubject/v1/save-phonics?id=285'
    run = Runmain(url,headers,'post',data).run_main()
    print(run)

unittest测试框架使用

详细用法请参考:https://www.cnblogs.com/huaerye/p/9361892.html

在test_method.py文件中则创建测试类以及test方法,在test方法中调用demo.py中的run_main方法,即使用requests模块向传递的接口url地址和请求方式以及请求体发送对应的请求,这里使用setUp方法则是利用其优先调用而对RunMain类进行实例化

import unittest
from demo import Runmain
class TestMethod(unittest.TestCase):
    def test_01(self):
        url = 'https://oapi.t.blingabc.com/bms/admin-api/specialsubject/v1/save-phonics?id=285'

        headers = {
        'token': "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJjb20ueGRmLmJsaW5nIiwiYXVkIjoiY2xpZW50IiwidXNlcmNvZGUiOiI5NTUxNjMxNyIsImV4cCI6MTU3NDMxNzY2NSwiaWF0IjoxNTczNzEyODY1fQ.UjNSQSQpP6umRubppSggYB1W-dkmnfBB5RMNRQUTS9a8IJDmURyPT1bMIWg5nwHL1z7GvvJ-Ch5PKGLEnwOh6g",
        'Content-Type': "application/json",
        }
        res1 = Runmain(url,headers,'GET').run_main()
        self.assertEqual(res1['code'],10000,"测试通过")   #添加断言
        print(res1)

    def test_02(self):
        url = 'https://oapi.blingabc.com/cms/user-api/student/homework/v2/homeworklist'
        headers = {
        'token': "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJjb20ueGRmLmJsaW5nIiwiYXVkIjoiY2xpZW50IiwidXNlcmNvZGUiOiI5NTUxNjMxNyIsImV4cCI6MTU3NDMxNzY2NSwiaWF0IjoxNTczNzEyODY1fQ.UjNSQSQpP6umRubppSggYB1W-dkmnfBB5RMNRQUTS9a8IJDmURyPT1bMIWg5nwHL1z7GvvJ-Ch5PKGLEnwOh6g",
        'Content-Type': "application/json",
        }
        data = {"stuNum":"795571161","page":1,"size": 5,"type":0}
        res2 = Runmain(url,headers,'post',data).run_main()
        self.assertEqual(res2['code'],10000,"测试通过")
        print(res2)

if __name__=='__main__':
    unittest.main()

    #3、还可以将要测试的case添加到unittest.TestSuite集合中执行想要执行的case,若想要全部都执行则需要一个一个的添加
    # suite = unittest.TestSuite()
    # suite.addTest(TestMethod("test_01"))

数据依赖

设计一个接口自动化测试框架

根据接口地址丶接口类型丶请求数据丶预期结果来进行设计,对于需要登录后才能进行操作的接口那么则需要进行header cookie等数据的传递,自动化测试的难点就是数据依赖。

python操作excel获得内容

python操作excel,需要安装两个包,分别是xlrd和xlwt这两个库,xlrd这个库是负责读取excel数据的,而xlwt库是负责向excel写入数据的;

安装方式:pip3 install xlrd

项目目录下创建utils工具包,在该包下创建operation_excel.py文件,在该文件中通过导入xlrd包,对excel表的数据进行读取操作

重构操作excel函数

根据上一步骤读取excel表的内容代码后,进行了一个简单的封装,提高代码的通用性,实现代码如下:

import xlrd
data = xlrd.open_workbook('../case/interface.xls')
tables = data.sheets()[0]    #获取表格数据对象
print(tables.nrows)           #打印表格行数
print(tables.cell_value(1,2))  #打印excel表格数据,需要传递所在坐标(x,y)

print("*"*50+"封装前后数据对比"+"*"*50)
class OperationExcel():
    def __init__(self,file_name=None,sheet_id=None):
        if file_name:
            self.file_name = file_name
            self.sheet_id = sheet_id
        else:
            self.file_name='../case/interface.xls'
            self.sheet_id = 0
        self.data = self.get_data()

    #获取sheets的内容
    def get_data(self):
        data = xlrd.open_workbook(self.file_name)
        tables = data.sheets()[self.sheet_id]
        return tables

    #获取单元格的行数
    def get_lines(self):
        tables = self.data
        return tables.nrows

    #获取某一个单元格的内容
    def get_cell_value(self,row,col):
        tables = self.data
        cell = tables.cell_value(row,col)
        return cell

if __name__=='__main__':
    opers = OperationExcel()
    print(opers.get_data().nrows)
    print(opers.get_lines())
    print(opers.get_cell_value(1,2))

结果对比:

学习操作json文件

如果把请求数据全部放到excel里面,数据量大时,看起来不是很美观,所以将请求数据单独弄成一个json文件,将入参名传入excel就可以了;

在项目下新建一个dataconfig文件用于存json文件,在该文件下创建student.json,文件内容如下:

 

在utils工具包下创建operation_json.py文件,在文件中对login.json文件内容进行读取操作,以及重构json代码:

import json

fp = open('../dataconfig/student.json')
res = json.load(fp)   #加载某个文件
print(res)
print(res['student_login'])
print(res['student_login']['mobile'])

print("="*50+"封装前后数据对比"+"="*50)

class OperationJson():
    def __init__(self, file_path="../dataconfig/student.json"):
        self.file_path = file_path
        self.data = self.get_data()

    def get_data(self):
        with open(self.file_path) as f:
            data = json.load(f)
            return data

    def get_key_words(self,key=None):
        if key:
            return self.data[key]
        else:
            return self.data
if __name__=='__main__':
    opjson = OperationJson()
    print(opjson.get_key_words())
    print(opjson.get_key_words('student_login'))
    print(opjson.get_key_words('student_login')['mobile'])

数据结果对比如下图:

 封装获取常量方法

 首先打开excel表格,查看需要获取的字段有哪些

对excel表的字段进行获取,在项目目录下创建名为data的python包,在该包下创建data_conf.py,代码就是简单的获取对应的变量值,具体如下

class global_var():
    id = '0'  # id
    description = '1'  # 接口描述
    url = '2'  # 接口地址
    run = '3'  # 是否运行
    request_way = '4'  # 请求方式
    request_header = '5'  #是否携带header
    case_depend = '6'  # case依赖
    response_data_depend = '7'  # 依赖的返回数据
    data_depend = '8'  #  数据依赖
    request_data = '9'  # 请求数据
    expect_result = '10'  # 预期结果
    reality_result = '11'  # 实际结果

def get_id():
    return global_var.id

def get_description():
    return global_var.description

def get_url():
    return global_var.url

def get_run():
    return global_var.run

def get_request_way():
    return global_var.request_way

def get_request_header():
    return global_var.request_header

def get_case_depend():
    return global_var.case_depend

def get_response_data_depend():
    return global_var.response_data_depend

def get_data_depend():
    return global_var.data_depend

def get_request_data():
    return global_var.request_data

def get_expect_result():
    return global_var.expect_result

def get_reality_result():
    return global_var.reality_result

封装获取接口数据

在data目录下创建get_data.py文件,在该文件中对excel表数据以及json数据结合上一步封装的常量方法整合后的实现,代码如下

from util.operation_excel import OperationExcel
from util.operation_json import OperationJson
from data import data_config

class GetData():
    def __init__(self):
        self.op_excel = OperationExcel()

    def get_case_lines(self):
        """获取表格行数"""
        return self.op_excel.get_lines()

    def get_is_run(self,row):
        """获取case是否运行"""
        flag = None
        col = int(data_config.get_run())
        run_model = self.op_excel.get_cell_value(row.col)
        if run_model == 'yes':
            flag = True
        else:
            flag = False
        return flag

    def get_is_header(self,row):
        """是否携带header"""
        col = data_config.get_request_header()
        header = self.op_excel.get_cell_value(row,col)
        if header != 'yes':
            return data_config.get_request_header()
        else:
            return None

    def get_request_method(self,row):
        """获取请求方式"""
        col = data_config.get_request_way()
        request_method = self.op_excel.get_cell_value(row,col)
        return request_method


    def get_request_url(self,row):
        """获取url地址"""
        col = data_config.get_url()
        url = self.op_excel.get_cell_value(row,col)
        return url

    def get_request_data(self,row):
        """获取请求数据"""
        col = data_config.get_url()
        request_data = self.op_excel.get_cell_value(row,col)
        if request_data == '':
            return None
        return request_data


    def get_header_value(self, row):
        """通过excel中的关键字去获取json数据"""
        op_json = OperationJson()
        data = op_json.get_key_words(self.get_request_data(row))
        return data


    def get_expect_data(self,row):
        """获取预期结果数据"""
        col = data_config.get_expect_result()
        expect_data = self.op_excel.get_cell_value(row,col)
        if expect_data == '':
            return True
        return expect_data

post、get基类的封装

在util文件下新创建了run_method.py文件,将开始的demo文件复制了过来,其他未作改动,headers默认参数设置为了None,用时可传入headers参数;

import requests
import json

class Runmain():
    def __init__(self,url,method,headers=None,params=None,data=None):
        self._url = url
        self._params = params
        self._data = data
        self._headers = headers
        self._method = method

    def send_get(self,url,params,headers):
        res = requests.get(url=url,params=params,headers=headers).json()
        #return json.dumps(res,sort_keys=True,indent=2)
        return res
    def send_post(self,url,data,headers):
        res = requests.post(url=url,json=data,headers=headers).json()
        return json.dumps(res,sort_keys=True,indent=4)

    def run_main(self):
        if self._method == 'GET':
            return self.send_get(self._url,self._params,self._headers)
        else:
            return self.send_post(self._url,self._data,self._headers)

if __name__=='__main__':

    url = 'https://oapi.t.blingabc.com/bms/admin-api/studentPreview/v1/myPreviews'
    headers = {
        'token': "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJjb20ueGRmLmJsaW5nIiwiYXVkIjoiY2xpZW50IiwidXNlcmNvZGUiOiI5NTUxNjMxNyIsImV4cCI6MTU3NDMzMDY5NiwiaWF0IjoxNTczNzI1ODk2fQ.yWaCaeOzZfVGokA7D7wrGeItcKPeyuythWIU52_1-rqZ9vEpYWRl6EYmq5thebccD0SecVpu6qLZm3NZu9DIqQ",
        'Content-Type': "application/json",
        'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36"
        }

    data = {"stuNum":"955163171","page":1,"size":5,"type":2}
    # url = 'https://oapi.t.blingabc.com/bms/admin-api/specialsubject/v1/save-phonics?id=285'
    run = Runmain(url,'post',headers,data).run_main()
    print(run)

主流程封装及错误解决调试

猜你喜欢

转载自www.cnblogs.com/huaerye/p/11869162.html