swagger 自動生成接口測試用例



---整體更新一波---
  1.實際工作中,因為要動手輸入的地方比較多,自動生成的異常接口用例感覺用處不大,就先去掉了,只保留了正常的;
  2.接口有改動的,如果開發人員沒有及時告知或沒有詳細告知,會增加一些不必要的麻煩,所以增加了文件對比功能;

目錄:
  

 

case_generate.py
import sys

sys.path.append('D:\Interface_framework_Beauty')

import requests
import os
from common.operation_excel import Write_excel  # 寫入excel模塊
from common.logger import Log  # 打印日志模塊
from common.processing_json import write_data  # 寫入json文件模塊
from common.difference import diff_excel, diff_json
from common import read_config

title_list = []

old_excel_path = os.path.abspath(
    os.path.dirname(os.path.dirname(__file__))) + '\\case_generate' + '\\data_old' + '\\demo_api.xlsx'
excel_path = os.path.abspath(
    os.path.dirname(
        os.path.dirname(__file__))) + '\\case_generate' + '\\data_new' + '\\demo_api.xlsx'  # case path
old_json_path = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) + '\\case_generate' + '\\data_old'
json_path = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) + '\\case_generate' + '\\data_new'


class AnalysisJson:
    """swagger自動生成測試用例"""

    def __init__(self, url_json):
        self.url_json = url_json
        r = requests.get(self.url_json + '/v2/api-docs?group=sign-api').json()
        self.title = r['info']['description']
        write_data(r, '{}.json'.format(self.title))
        self.interface_params = {}
        self.log = Log()
        self.row = 2  # 寫入excel起始行數
        self.num = 1  # case id
        global title_list, json_path
        if self.check_data(r):
            self.json_path = os.path.abspath(
                os.path.dirname(
                    os.path.dirname(__file__))) + '\\case_generate' + '\\data_new' + '\\{}_data.json'.format(
                self.title)  # json file path,執行多個url的情況,區分生成的json文件
        self.data = r['paths']  # paths中的數據是有用的

        title_list.append(self.title)

    def check_data(self, r):
        """檢查返回的數據是否是dict"""
        if not isinstance(r, dict):
            self.log.info('swagger return json error.')
            return False
        else:
            return True

    def retrieve_data(self):
        """主函數"""
        global body_name, method
        for k, v in self.data.items():
            method_list = []
            for _k, _v in v.items():
                interface = {}
                if not _v['deprecated']:  # 接口是否被棄用
                    method_list.append(_k)
                    api = k  # api地址
                    if len(method_list) > 1:  # api地址下的請求方式不止一個的情況
                        for i in range(len(method_list)):
                            body_name = api.replace('/', '_') + '_' * i  # json文件對應參數名稱,excel中body名稱
                            method = method_list[-1]  # 請求方式 同一個api地址,不同請求方式
                    else:
                        body_name = api.replace('/', '_')
                        method = _k
                    self.interface_params = self.retrieve_excel(_v, interface, api)
                else:
                    self.log.info('interface path: {}, case name: {}, is deprecated.'.format(k, _v['description']))
                    break
        if self.interface_params:
            write_data(self.interface_params, self.json_path)  # 參數寫入json文件

    def retrieve_excel(self, _v, interface, api):
        """解析參數,拼接為dict--准備完成寫入excel的數據"""
        parameters = _v.get('parameters')  # 未解析的參數字典
        if not parameters:  # 確保參數字典存在
            parameters = {}
        case_name = _v['summary']  # 接口名稱
        tags = _v['tags'][0]  # 標簽名稱
        params_dict = self.retrieve_params(parameters)  # 處理接口參數,拼成dict形式
        if params_dict and parameters != {}:  # 單個或多個參數
            interface['row_num'] = self.row  # 寫入excel時的所在行
            interface['id'] = 'test_' + str(self.num)  # case id
            interface['tags'] = tags  # 標簽名稱
            interface['name'] = case_name
            _type = 'json'  # 參數獲取方式
            interface['method'] = method  # 請求方式
            interface['url'] = self.url_json + api  # 拼接完成接口url
            interface['headers'] = 'yes'  # 是否傳header
            interface['body'] = body_name
            interface['type'] = _type
            self.num += 1
            self.row += 1
            self.interface_params[body_name] = params_dict
            self.write_excel(interface, excel_path)  # 參數寫入excel
        else:  # 沒有參數
            _type = 'data_old'
            interface['name'] = case_name
            interface['row_num'] = self.row
            interface['id'] = 'test_' + str(self.num)
            interface['tags'] = tags
            interface['method'] = method
            interface['url'] = self.url_json + api
            interface['headers'] = 'yes'
            interface['body'] = ''
            interface['type'] = _type
            self.num += 1
            self.row += 1
            self.interface_params[body_name] = params_dict
            self.write_excel(interface, excel_path)
        return self.interface_params

    def retrieve_params(self, parameters):
        """處理參數,轉為dict"""
        params = ''
        _in = ''
        for each in parameters:
            _in += each.get('in') + '\n'  # 參數傳遞位置
            params += each.get('name') + '\n'  # 參數
        _in = _in.strip('\n')
        _in_list = _in.split('\n')
        params = params.strip('\n')
        params_list = params.split('\n')
        del_list = params_list.copy()
        for i in range(len(_in_list)):
            if _in_list[i] == 'header':
                params_list.remove(del_list[i])  # 只保存在body傳的參數
        test_list = params_list.copy()
        params_dict = dict(zip(params_list, test_list))  # 把list轉為dict
        return params_dict

    def write_excel(self, interface, filename):
        """把dict中的值寫入對應的excel行中"""
        wt = Write_excel(filename, self.title)
        try:
            wt.write(interface['row_num'], 1, interface['id'])
            wt.write(interface['row_num'], 2, interface['tags'])
            wt.write(interface['row_num'], 3, interface['name'])
            wt.write(interface['row_num'], 4, interface['method'])
            wt.write(interface['row_num'], 5, interface['url'])
            wt.write(interface['row_num'], 7, interface['headers'])
            wt.write(interface['row_num'], 8, interface['body'])
            wt.write(interface['row_num'], 10, interface['type'])
            self.log.info('Interface case id {},write to excel file successfully!'.format(interface['id']))
        except Exception as e:
            self.log.info('Failure of interface use case to write to excel file! error:{}\n'.format(e))
            return


def diff_file():
    """對比文件"""
    global title_list
    for title in title_list:
        diff_excel(old_excel_path, excel_path, title)
        diff_json(os.path.join(old_json_path, '{}_data.json'.format(title)),
                  os.path.join(json_path, '{}_data.json'.format(title)), title)


if __name__ == '__main__':
    url = read_config.generate_url.split(',')
    for i in url:
        # url_json = i + '/v2/api-docs?group=sign-api'  # json swagger url地址
        AnalysisJson(i).retrieve_data()
    diff_file()

difference.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2019/3/17 21:35
# @Author  : lixiaofeng
# @File    : difference.py
# @Software: PyCharm
# @desc    : 對比接口excel, json更新

import xlrd, time, difflib, sys, os
from common.logger import Log, report_path

log = Log()


def diff_excel(ori_path, tar_path, sub_name):
    """比較excel文件"""
    success = 0  # 匹配一致數量
    fail = 0  # 匹配不一致數量
    origin_xls = {}  # 存儲源xls文件
    target_xls = {}  # 比對的xls文件
    wb_ori = xlrd.open_workbook(ori_path)  # 打開原始文件
    wb_tar = xlrd.open_workbook(tar_path)  # 打開目標文件
    log.info(':【開始比對】...' + '\n')  # 寫入開始時間

    try:
        sheet_ori = wb_ori.sheet_by_name(sub_name)
        sheet_tar = wb_tar.sheet_by_name(sub_name)
        if sheet_ori.name == sheet_tar.name:
            # sheet表名
            if sheet_ori.name == sub_name:
                # 先將數存入dictionary中dictionary(rows:list)
                # 第一行存儲表頭
                # 源表取一行數據與目標表全表進行比對如果表中存在主鍵可以用主鍵進行索引
                # 數據從excel第3行開始
                for rows in range(1, sheet_ori.nrows):
                    orign_list = sheet_ori.row_values(rows)  # 源表i行數據
                    target_list = sheet_tar.row_values(rows)  # 目標表i行數據
                    origin_xls[rows] = orign_list  # 源表寫入字典
                    target_xls[rows] = target_list  # 目標表寫入字典
                if origin_xls[1] == target_xls[1]:
                    log.info('>>>>>>>>>>>>>>>>>>> 表頭一致')
                for ori_num in origin_xls:
                    flag = 'false'  # 判斷是否一致標志
                    for tar_num in target_xls:
                        if origin_xls[ori_num] == target_xls[tar_num]:
                            flag = 'true'
                            break  # 如果匹配到結果退出循環
                    if flag == 'true':  # 匹配上結果輸出后台日志
                        success += 1
                    else:  # 匹配不上將源表中行記錄寫入log
                        fail += 1
                        data = origin_xls[ori_num]
                        logstr = '【不一致】row<' + str(ori_num) + '>:' + str(data)
                        log.info(logstr)
                logstr = '【比對完成】總記錄數:{:d}條,一致:{:d}條,不一致:{:d}條'.format(ori_num, success, fail)
                log.info(logstr)
        else:
            errmsg = '' + sub_name + '】子表名不一致'
            log.info(errmsg)
    except Exception as err:
        log.info(str(err))  # 輸出異常


# 創建打開文件函數,並按換行符分割內容
def read_json(filename):
    try:
        with open(filename, 'r') as fileHandle:
            text = fileHandle.read().splitlines()
        return text
    except IOError as e:
        log.error("Read file Error:" + e)
        sys.exit()


# 比較兩個文件並輸出到html文件中
def diff_json(filename1, filename2, name):
    text1_lines = read_json(filename1)
    text2_lines = read_json(filename2)
    d = difflib.HtmlDiff()
    # context=True時只顯示差異的上下文,默認顯示5行,由numlines參數控制,context=False顯示全文,差異部分顏色高亮,默認為顯示全文
    result = d.make_file(text1_lines, text2_lines, filename1, filename2, context=True)
    # 內容保存到result.html文件中
    log.info('json數據比對結果寫入html中.')
    with open(os.path.join(report_path, '{}_diff.html'.format(name)), 'w') as result_file:
        result_file.write(result)


if __name__ == '__main__':
    for i in ['前台api', '后台api']:
        diff_excel(r'G:\Interface_framework_Beauty\case_generate\data_old\demo_api.xlsx',
                   'G:\Interface_framework_Beauty\case_generate\data_new\demo_api.xlsx', '{}'.format(i))
    diff_json('G:\Interface_framework_Beauty\case_generate\data_old\前台api_data.json',
              'G:\Interface_framework_Beauty\case_generate\data_new\前台api_data.json', '')
 
        

執行成功后自動生成的 case,因為我使用的是ddt+requests+unittest框架,所以要把case集成到excel中。斷言什么的需要手動輸入...

 

data.json文件。使用的參數值需要手動輸入...

 

生成的日志文件。從日志文件可以看出,case條數和對應的json參數數量是一致的.

 

 可以根據生成的對比結果來修改接口數據

excel文件生成的log對比結果:

 json文件生成的html對比結果:

 

各位大大有其他好的方法,歡迎留言一起討論。

 

 

--------------------假裝這里是分割線---------------------

writeExcel.py 文件
# coding:utf-8
from openpyxl import load_workbook
import openpyxl
from openpyxl.styles import Font, colors


class Write_excel(object):
    """修改excel數據"""

    def __init__(self, filename):
        self.filename = filename
        self.wb = load_workbook(self.filename)
        self.ws = self.wb.active  # 激活sheet

    def write(self, row_n, col_n, value):
        """寫入數據,如(2,3,"hello"),第二行第三列寫入數據"hello\""""
        ft = Font(color=colors.RED, size=12, bold=True)
        # 判斷值為錯誤時添加字體樣式
        if value in ['fail', 'error'] or col_n == 12:
            self.ws.cell(row_n, col_n).font = ft
        if value == 'pass':
            ft = Font(color=colors.GREEN)
            self.ws.cell(row_n, col_n).font = ft
        self.ws.cell(row_n, col_n).value = value
        self.wb.save(self.filename)


if __name__ == "__main__":
    # copy_excel("demo_api.xlsx", "test111.xlsx")
    wt = Write_excel("test111.xlsx")
    wt.write(4, 5, "HELLEOP")
    wt.write(4, 6, "HELLEOP")
processingJson.py 文件
import json
from common.logger import Log
from jsonpath_rw import jsonpath, parse


def write_data(res, json_path):
    """把處理后的參數寫入json文件"""
    if isinstance(res, dict):
        with open(json_path, 'w', encoding='utf-8') as f:
            json.dump(res, f, indent=4)
            Log().info('Interface Params Total:{} ,write to json file successfully!\n'.format(len(res)))
    else:
        Log().info('{} Params is not dict.\n'.format(write_data.__name__))

 

logger.py 參考另一篇即可:python logging模塊 輸出日志和過期清理


此功能已集成到 EasyTest測試平台 中,歡迎大家體驗~~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM