#!/usr/bin/python # -*- coding: UTF-8 -*- import xlrd import requests import json import logging import smtplib from email.mime.text import MIMEText from email.utils import formataddr import jsonpath import sys import traceback #日志定义 logging.basicConfig(level=logging.DEBUG, # log level format='[%(asctime)s] %(levelname)s [%(funcName)s: %(filename)s, %(lineno)d] %(message)s', # log格式 datefmt='%Y-%m-%d %H:%M:%S', # 日期格式 filename='log.txt', # 日志输出文件 filemode='a') # 追加模式 class Config: global PHP_API_DOMAIN #php接口域名 global JAVA_API_DOMAIN #java接口域名 global TEST_CASE_PATH #测试用例excel的路径 global TEST_CASE_LIST #测试用例转换后的集合<字典> global PARAMS #存储结果变量 global CURRENT_REQUEST_HEADER #存储当前请求的请求头 global CURRENT_REQUEST_PARAM #存储当前请求的请求数据 global ALL_REQUEST_RESULT global CURRENT_REQUEST_STATUS def __init__(self,php_api_domain,java_api_domain,test_case_path): self.PHP_API_DOMAIN = php_api_domain self.TEST_CASE_PATH = test_case_path self.JAVA_API_DOMAIN = java_api_domain self.TEST_CASE_LIST = [] self.PARAMS = {} self.CURRENT_REQUEST_HEADER = {} self.CURRENT_REQUEST_PARAM = {} self.ALL_REQUEST_RESULT = [] self.CURRENT_REQUEST_STATUS = True headers = {'Accept': 'application/json, text/javascript, */*', 'Accept-Encoding':'gzip, deflate, br', 'Accept-Language':'zh-CN,zh;q=0.9', 'Connection':'Keep-Alive', 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063'} class request_handler: test_case = {} result_obj = {} assert_obj = {} assert_result = True need_assert = True def __init__(self, test_case): self.test_case = test_case self.main() self.return_entity() def main(self): self.request(self.test_case) if self.need_assert: self.setting_param() def return_entity(self): return_entity = {} return_entity['成功状态'] = self.assert_result return_entity['请求结果数据'] = self.result_obj return_entity['断言结果'] = self.assert_obj return_entity['用例数据'] = self.test_case return_entity['请求参数'] = config.CURRENT_REQUEST_PARAM return_entity['请求头'] = config.CURRENT_REQUEST_HEADER logging.info(return_entity) if not self.assert_result: config.ALL_REQUEST_RESULT.append(return_entity) config.CURRENT_REQUEST_STATUS = False else: config.CURRENT_REQUEST_STATUS = True def request(self,test_case): try: if test_case['method'] == 'GET': self.result_obj = self.request_get(test_case) if test_case['method'] == 'POST': self.result_obj = self.request_post(test_case) self.assert_handler() except Exception as e: self.need_assert = False self.assert_result = False self.result_obj = {"status_code": "error", "error_message": e} traceback.print_exc() info = traceback.format_exc() print(info) def request_get(self,object): url = self.get_url(object['url'],object['type']) head = headers if isinstance(object['header'],list): head = self.get_config_param(object['header'], head) request_body = {} if isinstance(json.loads(object['data']),dict): request_body = self.get_config_param(json.loads(object['data']), request_body) print("GET URL:"+url) config.CURRENT_REQUEST_HEADER = head config.CURRENT_REQUEST_PARAM = request_body response = requests.get(url=url, params=request_body,headers=head) return {"status_code" : response.status_code, "response_content": response.text} def request_post(self,object): head = headers #将header中的数据添加到请求中 if isinstance(json.loads(object['header']),dict): head = self.get_config_param(json.loads(object['header']),head) url = self.get_url(object['url'], object['type']) #将data中的动态参数从共享参数中添加到数据中 request_body = {} if isinstance(json.loads(object['data']),dict): request_body = self.get_config_param(json.loads(object['data']),request_body) print("POST URL:" + url+";param:"+str(request_body)) config.CURRENT_REQUEST_HEADER = head config.CURRENT_REQUEST_PARAM = request_body response = requests.post(url, request_body, headers=head) return {"status_code": response.status_code, "response_content": response.text} def get_config_param(self,list,object): for param_name in list.keys(): param_value = list[param_name] if not str(param_value).startswith("$P_"): object[param_name] = param_value else: body_value = config.PARAMS[param_value] if param_value in config.PARAMS.keys() else param_value object[param_name] = body_value return object def get_url(self,path,type): request_url = (config.PHP_API_DOMAIN + '/' + path) if type == 'php' else (config.JAVA_API_DOMAIN + '/' + path) return request_url def assert_handler(self): test_case = self.test_case result_obj = self.result_obj self.assert_obj = {"测试用例名称:": test_case['case_name']} # 访问接口直接报错直接 if result_obj['status_code'] == 'error': self.assert_obj = dict(self.assert_obj.items(), {"请求状态:": "错误", "错误信息:": result_obj['error_message']}.items()) self.need_assert = False self.assert_result = False return # 状态大于300的异常直接处理 if result_obj['status_code'] >= 300: self.assert_obj['请求状态'] = result_obj['status_code'] self.assert_obj['错误信息'] = result_obj['response_content'] self.need_assert = False self.assert_result = False return # 请求状态为成功,判断业务状态 buiess_content = json.loads(result_obj['response_content']) expect_res = json.loads(test_case['expect_res']) # 校验规则 for ruler in expect_res: matcher = jsonpath.jsonpath(buiess_content, ruler['rule']) if isinstance(matcher,bool): self.assert_obj['请求状态'] = result_obj['status_code'] self.assert_obj['错误信息'] = '规则:' + ruler['rule'] + '值不匹配,期望是:' + str(ruler['value']) + ',返回是:' + str( matcher) self.assert_result = False break elif len(matcher) == 0: self.assert_obj['请求状态'] = result_obj['status_code'] self.assert_obj['错误信息'] = '规则:' + ruler['rule'] + '提取出的数组长度为0' self.assert_result = False break elif ruler['type'] == 'value': # 对值进行比较 if matcher[0] == ruler['value']: continue else: self.assert_obj['请求状态'] = result_obj['status_code'] self.assert_obj['错误信息'] = '规则:' + ruler['rule'] + '值不匹配,期望是:' + str(ruler['value']) + ',返回是:' + str( matcher[0]) self.assert_result = False break elif ruler['type'] == 'length': # 对数组长度进行比较 if len(matcher) == ruler['value']: continue else: self.assert_obj['请求状态'] = result_obj['status_code'] self.assert_obj['错误信息'] = '规则:' + ruler['rule'] + '大小不匹配,期望是:' + str(ruler['value']) + ',返回是:' + str( len(matcher)) self.assert_result = False break else: self.assert_obj['请求状态'] = result_obj['status_code'] self.assert_obj['错误信息'] = '规则:' + ruler['rule'] + '错误' self.assert_result = False break def setting_param(self): actives = json.loads(self.test_case['active']) buiess_content = json.loads(self.result_obj['response_content']) for active in actives: try: p_name = active['p_name'] p_value = jsonpath.jsonpath(buiess_content, active['p_value']) if isinstance(p_value, bool): p_value = '' elif len(p_value) == 0: p_value = '' else: p_value = p_value[0] config.PARAMS[p_name] = p_value except Exception as e: traceback.print_exc() info = traceback.format_exc() print(info) def read_excel(): wb = xlrd.open_workbook(config.TEST_CASE_PATH) sh = wb.sheet_by_name('Sheet1') #处理 Excel的数据 for row_ndex in range(sh.nrows): test_case = dict(zip(sh.row_values(0), sh.row_values(row_ndex))) try: if row_ndex == 0: continue request_handler(test_case) if test_case['error_continue'] == 0 and not config.CURRENT_REQUEST_STATUS: break except Exception as e: traceback.print_exc() info = traceback.format_exc() print(info) #config.ALL_REQUEST_RESULT.append({"测试用例": test_case, "请求异常": e}) #发送邮件通知成功与否 message = '' for result_record in config.ALL_REQUEST_RESULT: message += json.dumps(result_record,ensure_ascii=False) +'\n\n\n' send_email(message) def send_email(message): if len(message) == 0: return my_sender = '[email protected]' # 发件人邮箱账号 my_pass = 'TongZhi@1218' # 发件人邮箱密码 my_user = '[email protected]' # 收件人邮箱账号,我这边发送给自己 ret = True try: msg = MIMEText(message, 'plain', 'utf-8') msg['From'] = formataddr(["小课接口测试报告", my_sender]) # 括号里的对应发件人邮箱昵称、发件人邮箱账号 msg['To'] = formataddr(["250", my_user]) # 括号里的对应收件人邮箱昵称、收件人邮箱账号 msg['Subject'] = "小课接口测试报告" # 邮件的主题,也可以说是标题 server = smtplib.SMTP_SSL("imap.exmail.qq.com", 465) # 发件人邮箱中的SMTP服务器,端口是25 server.login(my_sender, my_pass) # 括号中对应的是发件人邮箱账号、邮箱密码 server.sendmail(my_sender, [my_user, ], msg.as_string()) # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件 server.quit() # 关闭连接 except Exception as e: # 如果 try 中的语句没有执行,则会执行下面的 ret=False traceback.print_exc() info = traceback.format_exc() print(info) ret = False if ret: print("发送邮件成功") else: print('发送邮件失败') #config = Config(r'http://test-keepapi.kuaizaixuetang.com', r'http://192.168.1.221:8917',r'G:\python_project\test_api\test_case.xlsx') if __name__ == '__main__': argv = sys.argv if len(sys.argv) != 4: print('参数个数不正确') php_api = argv[1] java_api = argv[2] excel_path = argv[3] config = Config(php_api, java_api, excel_path) read_excel()
EXCEL案列