---整體更新一波---
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測試平台 中,歡迎大家體驗~~~