美文网首页
基于python+requests+unittest实现的接口自

基于python+requests+unittest实现的接口自

作者: 十分元气 | 来源:发表于2019-01-17 19:00 被阅读0次

    第一篇简书文章献给你,笔芯~

    背景简介

    最近在做接口测试,每次新功能提交测试,有大量的接口,有些接口参数有几十个,转化成用例,除了每个参数基础的边界值、等价类校验外,还涉及很多业务逻辑的比对测试。由于团队提供的API接口在swagger上面,每次测试在swagger上拼参数测试确实很方便,但是没有个记录,测试完了除非每个团队成员都对接口参数有保存,后续再要验证时要重新拼参数或是找同事拿已经拼好的参数,增加时间成本,而且要回归验证有需要再重新调一次,考虑到这些,做了一些需求调研,决定使用python+requests+unittest实现读取Excel用例自动执行请求。项目落成,在此做个记录,当然仍有许多不足之处需改进。

    需求分析

    要做一个东西,当然是要先搞清楚需求,即我们的现状,要实现怎样的效果,搞清楚了要实现什么,再来一步一步的任务拆分,然后想办法实现。

    首先,开发提供给我们测试的接口是通过swagger自动生成,没有特定的接口文档,swagger上有每个接口详细的参数描述等信息。接口请求类型主要有GET、POST、PUT、DELETE,针对每个类型的接口,传参类型有所不同,不能用通用的requests传参来做拼接请求,如下:


    params_type.png

    如果类型为URL Path的,做请求时就需要拿到base_url+URL Path,拼接好后作为请求的url;
    如果类型为Query的,就需要把参数以key-value的形式进行传参;等等...
    依此,设计Excel模板如下:


    Excel模板.png
    每个团队成员只需要在Excel里面写一次用例,执行的时候记录下每个传参、请求的基础url,预期结果,之后就可以自动回归啦~

    接下来就是要怎么实现这个过程了...

    实现

    就像把大象塞冰箱里面需要几个步骤一样,打开冰箱、把大象塞进去、关上冰箱....(⊙﹏⊙)b....大象根本就塞不下一般的冰箱好不啦~

    言归正传,怎样实现这个过程:

    1.遍历excel,读取数据
    2.处理读取到的数据,拿到我们想要的数据
    3.拼接请求,发送request请求
    4.拿到response状态值,对比excel预期结果是否一致

    架构如图(也说不上什么架构哈~)


    项目结构.png

    说明:
    ·operate_excel.py:封装一些操作excel数据表的方法
    ·get_data.py:封装获取excel值的方法
    ·data_config.py:配置excel的固定列,封装获取对应列的方法
    ·handle_requests.py:封装request请求
    ·run.py:主函数,根据拿到的请求类型判断,拼装请求url及参数自动发送请求,返回实际请求的status_code以及excel的expect。然后作为参数传递给unittest的test方法自动断言

    data_config.py:

    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    """
    获取Excel每列
    """
    
    class global_var:
        Id = '0'
        interface_name = '1'
        case_name = '2'
        case_paramas_type = '3'
        case_method = '4'
        case_headers = '5'
        parameters = '6'
        query = '7'
        body = '8'
        request_url ='9'
        expect = '10'
        result = '11'
        sql1 = '12'
        sql2 = '13'
    
    def get_id():
        return global_var.Id
    
    def get_url():
        return global_var.request_url
    
    def get_interface_name():
        return global_var.interface_name
    
    def get_case_name():
        return global_var.case_name
    
    def get_case_params_type():
        return global_var.case_paramas_type
    
    def get_method():
        return global_var.case_method
    
    def get_headers():
        return global_var.case_headers
    
    def get_parameters():
        return global_var.parameters
    
    def get_query():
        return global_var.query
    
    def get_body():
        return global_var.body
    
    def get_expect():
        return global_var.expect
    

    get_data.py:

    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    """
    获取单元格中的内容
    """
    
    from NewTest.public.operate_excel import OperateExcel
    from NewTest.public import data_config
    import xlrd
    
    class GetData:
    
        def __init__(self,file_name):
            self.opera_excel = OperateExcel(file_name)
    
        # 获取Excel行数,即case个数
        def get_case_linese(self):
            return self.opera_excel.get_lines()
    
        # 获取是否携带headers
        def is_header(self,row):
            col = int(data_config.get_headers())
            header = self.opera_excel.get_cell_value(row,col)
            if header != '':
                return header
            else:
                return None
    
        # 获取请求方式
        def get_request_method(self,row):
            col = int(data_config.get_method())
            request_method = self.opera_excel.get_cell_value(row,col)
            return request_method
    
        # 获取请求url
        def get_request_url(self,row):
            col = int(data_config.get_url())
            request_url = self.opera_excel.get_cell_value(row,col)
            if request_url == '':
                return None
            else:
                return request_url
    
        # 获取请求query
        def get_request_query(self,row):
            col = int(data_config.get_query())
            reuqest_query = self.opera_excel.get_cell_value(row,col)
            if reuqest_query == '':
                return None
            else:
                return reuqest_query
    
        # 获取请求body
        def get_request_body(self,row):
            col = int(data_config.get_body())
            request_body = self.opera_excel.get_cell_value(row,col)
            if request_body == '':
                return None
            else:
                return request_body
    
        # 获取期望结果
        def get_expect_result(self,row):
            col = int(data_config.get_expect())
            expect_result = self.opera_excel.get_cell_value(row,col)
            if expect_result != '':
                return expect_result
            else:
                return None
    
        # 获取用例参数方式
        def get_case_params_type(self,row):
            col = int(data_config.get_case_params_type())
            case_paramas_type = self.opera_excel.get_cell_value(row,col)
            return case_paramas_type
    
        # 获取parameters
        def get_request_params(self,row):
            col = int(data_config.get_parameters())
            request_params = self.opera_excel.get_cell_value(row,col)
            return request_params
    
        def get_case_id(self,row):
            col = int(data_config.get_id())
            id = self.opera_excel.get_cell_value(row,col)
            return id
    

    operate_excel.py:

    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    
    import xlrd
    
    class OperateExcel:
    
        def __init__(self,file_name,sheet_id=0):
    
            self.file_name = file_name
            self.sheet_id = sheet_id
            self.data = self.get_data_contents()
            self.new_path = '../NewTest/report/'
    
        # 获取sheet内容
        def get_data_contents(self):
            data = xlrd.open_workbook(self.file_name)
            table = data.sheet_by_index(self.sheet_id)
            return table
    
        # 获取单元格行数
        def get_lines(self):
            tables = self.get_data_contents()
            return tables.nrows
    
        # 获取某个单元格内容
        def get_cell_value(self,row,col):
            return self.data.cell_value(row,col)
    

    handle_requests.py:

    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    """
    封装get/post请求
    """
    
    import requests
    
    class SendRequest:
    
        def request_main(self, method, request_url, params=None, data=None, headers=None):
    
            try:
    
                res = requests.request(method, request_url, params=params, data=data, headers=headers, timeout=5)
    
                return res
            except (requests.ConnectionError, requests.HTTPError, requests.URLRequired, requests.Timeout,
                    requests.ConnectTimeout), e:
                print e
    

    run.py

    #!/urs/bin/python
    # -*- coding:utf-8 -*-
    
    from public.get_data import GetData
    from public.handle_requests import SendRequest
    import json
    import requests
    from nose_parameterized import parameterized
    import unittest
    
    class TestRunCase():
    
        def __init__(self, file_name):
            self.run_request = SendRequest()
            self.data = GetData(file_name)
            self.path = file_name
    
        def get_params(self):
    
            param_dic = []
            try:
    
                rows_count = self.data.get_case_linese()  # 获取用例excel条数
                for i in range(1, rows_count):
                    method = self.data.get_request_method(i)
                    type = self.data.get_case_params_type(i)
                    query = self.data.get_request_query(i)
                    body = self.data.get_request_body(i)
                    url = self.data.get_request_url(i)
                    params = self.data.get_request_params(i)
    
                    if type == "URL Path":
                        request_url = url + str(params)
                        params = None
                        data = None
                        headers = None
                    elif type == "No Type":
                        request_url = url
                        params = None
                        data = None
                        headers = None
                    elif type == "Query":
                        request_url = url
                        params = json.loads(query)
                        data = None
                        headers = None
                    elif type == "URL Path And Query":
                        request_url = url + params
                        params = json.loads(query)
                        data = None
                        headers = None
                    elif type == "Body":
                        request_url = url
                        body = json.loads(body)
                        params = None
                        data = json.dumps(body)
                        headers = None
                    else:
                        print "请求方式不在范围内!"
    
                    response = self.run_request.request_main(method, request_url, params=params, data=data,
                                                             headers=headers)
                    actual_results = response.status_code
                    expect_results = int(self.data.get_expect_result(i))
                    case_id = i + 1
    
                    param_dic.append((case_id, expect_results, actual_results))
    
                return param_dic
    
            except (requests.ConnectionError, requests.HTTPError, requests.URLRequired, requests.Timeout,
                    requests.ConnectTimeout) as e:
                print e
    
    path = "/Users/shifenyuanqi/Desktop/test.xlsx"
    params_list = TestRunCase(path).get_params()
    print params_list
    
    
    class TestRun(unittest.TestCase):
    
        @parameterized.expand(params_list)
        def test_run(self, name, expect_res, actual_res):
            self.assertEqual(expect_res, actual_res)
    
    

    最后run一波,自动遍历excel的每条case执行请求生成结果:


    run_results.png

    当然还有写入excel执行结果啦,生成测试报告,自动持续集成到Jenkins这些这里就暂时不赘述了~~

    相关文章

      网友评论

          本文标题:基于python+requests+unittest实现的接口自

          本文链接:https://www.haomeiwen.com/subject/dwpidqtx.html