def http_request(self, interface_url, headerdata, interface_parm, request_type): """ :param interface_url: 接口地址 :param headerdata: 请求头文件 :param interface_parm: 接口请求参数 :param request_type: 请求类型 :return: 字典形式结果 """ try: if request_type == 'get' or request_type == 'GET': result = self.__http_get(interface_url, headerdata, interface_parm) MyLog.debug('用例发送消息URL:%s\n' '用例发送消息头:%s\n' '用例发送消息体:%s\n' % (interface_parm, headerdata, interface_parm)) elif request_type == 'post' or request_type == 'POST': result = self.__http_post(interface_url, headerdata, interface_parm) MyLog.debug('用例发送消息URL:%s\n' '用例发送消息头:%s\n' '用例发送消息体:%s\n' % (interface_parm, headerdata, interface_parm)) else: result = {'code': '1000', 'message': '请求类型错误', 'data': []} except Exception as e: # traceback.print_exc() MyLog.error(e) return result
def get_compare_params(self, result_interface): """ :param result_interface: HTTP返回包数据 :return: 返回码code,返回信息message,数据data """ try: if result_interface.startswith('{') and isinstance( result_interface, str): temp_result_interface = json.loads( result_interface) # 将字符串类型转换为字典类型 self.result_list_response = temp_result_interface.keys() result = { 'code': '0000', 'message': '成功', 'data': self.result_list_response } else: result = { 'code': '1000', 'message': '返回包格式不合法', 'data': self.result_list_response } except Exception as e: result = {'code': '9999', 'message': '处理数据异常', 'data': []} MyLog.error(e) finally: return result
def __recur_params__(self, result_interface): """ 定义递归操作,将接口返回数据中的参数名写入列表中(去重) :return: """ try: if isinstance(result_interface, str) and result_interface.startswith('{'): temp_result_interface = json.loads(result_interface) self.__recur_params__(temp_result_interface) elif isinstance(result_interface, dict): # 入参是字典 for param, value in result_interface.items(): self.result_list_response.append(param) if isinstance(value, list): for param in value: self.__recur_params__(param) elif isinstance(value, dict): self.__recur_params__(value) else: continue else: pass except Exception as e: MyLog.error(e) result = {'code': '9999', 'message': '数据处理异常', 'data': []} return result return { 'code': '0000', 'message': '成功', 'data': list(set(self.result_list_response)) }
def __new__param(param): try: if isinstance(param, str) and param.startswith('{'): new_param = eval(param) elif param is None: new_param = '' else: new_param = param except Exception as e: new_param = '' MyLog.error(e) return new_param
def insert_data(self, condition, params): """ 定义表中插入操作 :param condition: insert 语句 :param params:数据,列表形式[('3','Tom','1 year 1 class','6'),('3','Jack','2 year 1 class','7')] :return:字典形式的批量插入数据结果 """ try: results = self.cur.executemany(condition, params) # 返回插入的数据条数 self.conn.commit() result = {'code': '0000', 'message': '执行批量插入操作成功', 'data': results} except Exception as e: self.conn.rollback() # 执行回滚操作 result = {'code': '9999', 'message': '执行批量插入操作异常', 'data': []} # print("数据库错误| Mysql Error %d: %s" % (e.args[0], e.args[1])) MyLog.error(e) return result
def readsheet(self, sheet_name): """ :param table_name: sheet表名,若table_name == None,则读取所有table中的数据 :return: 返回list[ {'id': 1.0, 'tags': '位置信息', 'name': '获取ip信息接口测试用例-1', 'method': 'get', 'url': 'http://ip.taobao.com/service/getIpInfo.php', 'headers': "{'Host':'ip.taobao.com'}", 'body': "{'ip':'63.223.108.4'}", 'type': 'json', 'return_status_code': '', 'return_text': ''}, {'id': 2.0, 'tags': '位置信息', 'name': '获取ip信息接口测试用例-2', 'method': 'get', 'url': 'http://ip.taobao.com/service/getIpInfo.php', 'headers': "{'Host':'ip.taobao.com'}", 'body': "{'ip':'127.0.0.1'}", 'type': 'json', 'return_status_code': '', 'return_text': ''} ] """ interfaces_list = [] try: if sheet_name is not None: sheet = self.xl.sheet_by_name(sheet_name) # 获取总列数 rows = sheet.nrows if rows >= 2: # 获取第一行数据,作为字典Key值 keys_list = sheet.row_values(0) for i in range(rows): if i >= 1: parmDict = dict(zip(keys_list, sheet.row_values(i))) interfaces_list.append(parmDict) result = { 'code': '0000', 'message': '执行批量excel查询表%s操作成功' % sheet_name, 'data': interfaces_list } return result else: print('表名为%s数据为空!' % sheet_name) result = { 'code': '0000', 'message': '执行批量excel查询操作失败,表名为%s数据为空' % sheet_name, 'data': [] } return result except xlrd.biffh.XLRDError as e: print('没有名称为%s的sheet' % sheet_name) MyLog.error('没有名称为%s的sheet' % sheet_name) result = { 'code': '9999', 'message': '执行批量excel查询操作失败,没有名称为%s的sheet' % sheet_name, 'data': [] } return result
def __http_post(self, interface_url, headerdata, interface_param): """ :param interface_url: 接口地址 :param headerdata: 请求头文件 :param interface_param: 接口请求参数 :return: 字典形式结果 """ try: if interface_url != '': temp_interface_param = self.__new__param(interface_param) if headerdata.get('Content-Type') == 'application/x-www-form-urlencoded': response = requests.post(url=interface_url, headers=headerdata, data=temp_interface_param, verify=False, timeout=10) if headerdata.get('Content-Type') == 'application/json': response = requests.post(url=interface_url, headers=headerdata, json=temp_interface_param, verify=False, timeout=10) if headerdata.get('Content-Type') == 'multipart/form-data': # files = {'file': open('upload.txt', 'rb')} response = requests.post(url=interface_url, headers=headerdata, files=temp_interface_param, verify=False, timeout=10) if response.status_code == 200: response_time = response.elapsed.microseconds / 1000 # 发起请求和响应到达的时间,单位ms result = {'code': '0000', 'message': '成功', 'data': response.text, 'response_time': response_time} else: result = {'code': '2004', 'message': '接口返回状态错误', 'data': []} elif interface_url == '': result = {'code': '2002', 'message': '接口地址参数为空', 'data': []} else: result = {'code': '2003', 'message': '接口地址错误', 'data': []} except Exception as e: result = {'code': '9999', 'message': '系统异常', 'data': []} MyLog.error(e) return result
def setvar(self, result_interface): """ :param result_interface: 接口返回参数 :return: """ if self.extra_key_list_str and \ self.extra_key_list_str.startswith("[") and \ self.extra_key_list_str.endswith("]"): try: extra_key_list = eval(self.extra_key_list_str) except Exception as e: MyLog.error(e) if result_interface and result_interface.startswith( '{') and isinstance(result_interface, str): temp_result_interface = json.loads( result_interface) # 将字符串类型转换为字典类型 for extra_key in extra_key_list: value_list = get_target_value(extra_key, temp_result_interface, tmp_list=[]) if len(value_list) == 1: for value in value_list: if isinstance(value, str): # 判断value是否是字符串 self.cache.set(extra_key, '\'' + value + '\'') elif isinstance(value, int): # 判断value是不是int类型 self.cache.set(extra_key, value) elif isinstance(value, dict): # 判断value是不是字典类型 self.cache.set(extra_key, value) else: MyLog.error('未处理的数据类型', value) MyLog.debug('接口返回值入参成功%s %s' % (extra_key, value)) elif len(value_list) == 0: MyLog.error('缓存数据设置错误,未找到对应返回值%s' % extra_key) elif len(value_list) > 1: # MyLog.error('value_list',value_list) MyLog.error('缓存数据设置错误,存在多个值') else: MyLog.error('接口返回值类型错误,无法将参数存入缓存') else: MyLog.debug('接口无缓存参数')
def op_sql(self, condition): """ 定义单条数据库操作,包含删除,更新操作 :param condition: SQL语句,该通用方法可用来代替updateone, deleteone :return: 字典形式 """ try: # condition.replace('"', '\"') self.cur.execute(condition) # 执行SQL语句 self.conn.commit() # 提交游标数据 result = {'code': '0000', 'message': '执行通用操作成功', 'data': []} except pymysql.Error as e: self.conn.rollback() # 执行回滚操作 result = {'code': '9999', 'message': '执行通用操作异常', 'data': []} print("数据库错误| Mysql Error %d: %s" % (e.args[0], e.args[1])) MyLog.error(e) return result
def export2excel(self, name_export): """ :param name_export: 待导出的接口名称,列表形式 :return: """ counts_export = len(name_export) # 导出总数 fail_export = [] # 导出失败接口列表 try: src = open_workbook(config.src_path + '/report/report_module.xls', formatting_info=True) destination = copy(src) dt = datetime.datetime.now().strftime("%Y%m%d%H%M%S") # 当前的时间戳 filepath = config.src_path + '/report/' + str(dt) + '.xls' destination.save(filepath) # 保存模板表格到新的目录下 for name_interface in name_export: cases_interface = self.db.select_all("SELECT * FROM case_interface " "WHERE case_status = 1 " "and name_interface = '%s'" % name_interface) if len(cases_interface.get('data')) != 0 and cases_interface.get('code') == '0000': src = open_workbook(filepath, formatting_info=True) destination = copy(src) sheet = destination.add_sheet(name_interface, cell_overwrite_ok=True) for col in range(0, len(self.field)): sheet.write(0, col, self.field[col]) # 获取并写入数据段信息到Sheet中 for row in range(1, len(cases_interface['data']) + 1): for col in range(0, len(self.field)): sheet.write(row, col, '%s' % cases_interface['data'][row - 1][col]) # 写数据到对应Excel表中 destination.save(filepath) elif len(cases_interface['data']) == 0 and cases_interface['code'] == '0000': fail_export.append(name_interface) else: fail_export.append(name_interface) result = {'code': '0000', 'message': '导出总数: %s , 失败数: %s' % (counts_export, len(fail_export)), 'data': fail_export} except Exception as e: MyLog.error(e) result = {'code': '9999', 'message': '导出过程异常|导出总数: %s , 失败数: %s' % (counts_export, len(fail_export)), 'data': fail_export} finally: return result
def getvar(self): """ 获取参数 :return:{key1:value1,key2:value2,...} """ sign = self.match_var() cache_value = {} if sign: for key in sign: value = self.cache.get(key) if value is not None: MyLog.debug('获取其他接口入参参数成功,参数名称为%s,参数值为%s' % (sign, value)) cache_value[key] = value # return self.cache.get(sign) else: MyLog.error('获取参数异常,缓存中没有%s的值' % sign) return cache_value else: MyLog.debug('该接口无${}标识') return None
def __init__(self, host_db='127.0.0.1', user_db='root', pwd_db='123456', name_db='test_interface', port_db=3306, link_type=0): """ 初始化数据库链接 :param host_db: 数据库服务主机 :param user_db: 数据库用户名 :param pwd_db: 数据库密码 :param name_db: 数据库名称 :param port_db: 端口号,整型数据 :param link_type: 连接类型,用户设置输出数据是元组还是字典,默认是字典,link_type = 0 :return:游标 """ try: if link_type == 0: self.conn = pymysql.connect( host=host_db, user=user_db, password=pwd_db, db=name_db, port=port_db, charset='utf8', cursorclass=pymysql.cursors.DictCursor) # 创建数据库连接,返回字典 else: self.conn = pymysql.connect(host=host_db, user=user_db, password=pwd_db, db=name_db, port=port_db, charset='utf8') # 创建数据库连接,返回元组 self.cur = self.conn.cursor() except pymysql.Error as e: print("创建数据库连接失败| Mysql Error %d: %s" % (e.args[0], e.args[1])) MyLog.error("创建数据库连接失败| Mysql Error %d: %s" % (e.args[0], e.args[1]))
def run(): logger = MyLog("开启日志线程记录").get_log() logpath = Log("获取日志路径").logPath reportName = logpath + "\/" + 'report.html' try: suit = set_case_suite() if suit is not None: logger.info("********TEST START********") with open(reportName, "w", encoding="UTF-8") as fp: fp.close() # with open(reportName,"wb") as fp: # runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title='Test Report', verbosity=2, description='Test Description') # runner.run(suit) #rnn = TestRunner() rnn = TestRunner(suite=suit, filename="report.html", report_dir=logpath, title="testreport", tester="cjx", desc="test schemer report") rnn.run() #全部重跑,所有失败的用例都将重跑2次 #rnn.rerun_run(count=3, interval=2) else: logger.info("Have no case to test.") except Exception as ex: logger.error(str(ex)) finally: logger.info("*********TEST END*********") # send test report by email on_off = readConfig.ReadConfig().get_email("on_off") if int(on_off) == 0: configEmail.Email().send_email() elif int(on_off) == 1: logger.info("不发送邮件给开发") elif int(on_off) == 2: logger.info("不发送邮") else: logger.info("Unknow state.")
def __http_get(self, interface_url, headerdata, interface_param): """ :param interface_url: 接口地址 :param headerdata: 请求头文件 :param interface_param: 接口请求参数 :return: 字典形式结果 """ try: if interface_url != '': temp_interface_param = self.__new__param(interface_param) # if interface_url.endswith('?'): # requrl = interface_url + temp_interface_param # else: # requrl = interface_url + '?' + temp_interface_param requrl = interface_url response = requests.get(url=requrl, headers=headerdata, verify=False, timeout=10, params=temp_interface_param ) if response.status_code == 200: response_time = response.elapsed.microseconds / 1000 # 发起请求和响应到达的时间,单位ms result = {'code': '0000', 'message': '成功', 'data': response.text, 'response_time': response_time} else: result = {'code': '3004', 'message': '接口返回状态错误', 'data': []} elif interface_url == '': result = {'code': '3002', 'message': '接口地址参数为空', 'data': []} else: result = {'code': '3003', 'message': '接口地址错误', 'data': []} except Exception as e: result = {'code': '9999', 'message': '系统异常', 'data': []} MyLog.error(result) MyLog.error(e) return result
def select_all(self, condition): """ 查询表中多条数据 :param condition: SQL语句 :return: 字典形式的批量查询结果 """ try: rows_affect = self.cur.execute(condition) if rows_affect > 0: # 查询结果返回数据大于0 self.cur.scroll(0, mode='absolute') # 将鼠标光标放回到初始位置 results = self.cur.fetchall() # 返回游标中所有结果 result = { 'code': '0000', 'message': '执行批量查询操作成功', 'data': results } else: result = {'code': '0000', 'message': '执行批量查询操作成功', 'data': []} except pymysql.Error as e: result = {'code': '9999', 'message': '执行批量查询异常', 'data': []} print("数据库错误| Mysql Error %d: %s" % (e.args[0], e.args[1])) MyLog.error("数据库错误| Mysql Error %d: %s" % (e.args[0], e.args[1])) return result
def select_one(self, condition): """ 查询表中单条数据 :param condition: SQL语句 :return: 字典形式的单条查询结果 """ try: rows_affect = self.cur.execute(condition) if rows_affect > 0: # 查询结果返回数据大于0 results = self.cur.fetchone() # 获取一条数据 result = { 'code': '0000', 'message': '执行单条查询操作成功', 'data': results } else: result = {'code': '0000', 'message': '执行单条查询操作成功', 'data': []} except pymysql.Error as e: result = {'code': '9999', 'message': '执行单条查询异常', 'data': []} print("数据库错误| Mysql Error %d: %s" % (e.args[0], e.args[1])) MyLog.error("数据库错误| Mysql Error %d: %s" % (e.args[0], e.args[1])) return result
def compare_code(self, result_interface): """ :param result_interface: HTTP返回数据包 :return: ,返回信息message,数据data """ try: if isinstance(result_interface, str) and result_interface.startswith('{'): temp_result_interface = json.loads( result_interface) # 将字符类型转换为字典类型 temp_code_to_compare = self.params_interface.get( 'code_to_compare') if temp_code_to_compare in temp_result_interface.keys(): if str(temp_result_interface.get( temp_code_to_compare)) == str( self.params_interface.get('code_expect')): result = { 'code': '0000', 'message': '关键字参数值相同', 'data': [] } print( "############", "UPDATE case_interface set code_actual=%s," "result_code_compare =%s where id =%s" % (str( temp_result_interface.get(temp_code_to_compare) ).replace("'", "\\'"), 1, self.id_case)) self.db.op_sql( "UPDATE case_interface set code_actual=%s," "result_code_compare =%s where id =%s" % (str( temp_result_interface.get(temp_code_to_compare) ).replace("'", "\\'"), 1, self.id_case)) elif str(temp_result_interface.get( temp_code_to_compare)) != str( self.params_interface.get('code_expect')): result = { 'code': '1003', 'message': '关键字参数值不相同', 'data': [] } print( "############", "UPDATE case_interface set code_actual='%s'," "result_code_compare =%s where id =%s" % (str( temp_result_interface.get(temp_code_to_compare) ).replace("'", "\\'"), 0, self.id_case)) self.db.op_sql( "UPDATE case_interface set code_actual='%s'," "result_code_compare =%s where id =%s" % (str( temp_result_interface.get(temp_code_to_compare) ).replace("'", "\\'"), 0, self.id_case)) else: result = { 'code': '1002', 'message': '关键字参数值比较出错', 'data': [] } self.db.op_sql( "UPDATE " " set code_actual='%s'," "result_code_compare =%s where id =%s" % (temp_result_interface.get(temp_code_to_compare), 3, self.id_case)) else: result = { 'code': '1001', 'message': '返回包数据无关键字参数', 'data': [] } self.db.op_sql( "UPDATE case_interface set result_code_compare =%s where id =%s" % (2, self.id_case)) else: result = {'code': '1000', 'message': '返回包格式不合法', 'data': []} self.db.op_sql( "UPDATE case_interface set result_code_compare =%s where id =%s" % (4, self.id_case)) except Exception as e: result = {'code': '9999', 'message': '关键字参数值比较异常', 'data': []} self.db.op_sql( "UPDATE case_interface set result_code_compare =%s where id =%s" % (9, self.id_case)) MyLog.error(e) finally: return result
class WindowsConnect(Connect): def __init__( self, windows_name: str, hwnd: int = 0, ): self.windows_name = windows_name if hwnd == 0: self.hwnd = win32gui.FindWindow(0, self.windows_name) else: self.hwnd = hwnd self.logger = MyLog('windows').get_logger() def connect(self): if self.hwnd == 0: self.logger.error('连接失败!请检查~ name:{}'.format(self.windows_name)) return None else: self.logger.info('连接成功!hwnd:{} name:{}'.format( self.hwnd, self.windows_name)) return self.hwnd @log def activate_window(self): user32 = ctypes.WinDLL('user32.dll') user32.SwitchToThisWindow(self.hwnd, True) def execute_command(self, com): ex = subprocess.Popen(com, stdout=subprocess.PIPE, shell=True) self.logger.debug('执行命令: {}'.format(com)) out, err = ex.communicate() status = ex.wait() self.logger.debug('命令结果: {}'.format(out.decode().strip())) self.logger.debug('状态: {}'.format(status)) return out.decode(), err, status def click_bg(self, pos, pos_end=None): """ 后台模拟点击 :param pos: 要点击的坐标 :param pos_end: 若不为空,则点击的是pos~pos_end之间的随机位置 :return: 无 """ pos_rand = proc_rand_pos(pos, pos_end) win32gui.SendMessage(self.hwnd, win32con.WM_MOUSEMOVE, 0, win32api.MAKELONG(*pos_rand)) win32gui.SendMessage(self.hwnd, win32con.WM_LBUTTONDOWN, 0, win32api.MAKELONG(*pos_rand)) time.sleep(random.randint(20, 80) / 1000) win32gui.SendMessage(self.hwnd, win32con.WM_LBUTTONUP, 0, win32api.MAKELONG(*pos_rand)) @log def drag_bg(self, pos1, pos2, cost_time=None): """ 后台拖拽 :param pos1: (x,y) 起点坐标 :param pos2: (x,y) 终点坐标 :param cost_time: 消耗时间 """ move_x = np.linspace(pos1[0], pos2[0], num=20, endpoint=True) move_y = np.linspace(pos1[1], pos2[1], num=20, endpoint=True) win32gui.SendMessage(self.hwnd, win32con.WM_LBUTTONDOWN, 0, win32api.MAKELONG(*pos1)) for i in range(20): x = int(round(move_x[i])) y = int(round(move_y[i])) win32gui.SendMessage(self.hwnd, win32con.WM_MOUSEMOVE, 0, win32api.MAKELONG(x, y)) t = 0.01 * random.random() time.sleep(t) cost_time -= t * 1000 if cost_time > 0: time.sleep(cost_time / 1000) win32gui.SendMessage(self.hwnd, win32con.WM_LBUTTONUP, 0, win32api.MAKELONG(*pos2))
def compare_params_complete(self, result_interface): """ 定义参数完整性的比较方法,将传参值与__recur_params 方法返回结果进行比较 :param result_interface: :return: 返回码Code,返回信息Message,数据data """ try: temp_compare_params = self.__recur_params__( result_interface) # 获取返回包的参数集 if temp_compare_params.get('code') == '0000': temp_result_list_response = temp_compare_params.get( 'data') # 获取接口返回参数去重列表 if self.params_to_compare.startswith('[') and isinstance( self.params_to_compare, str): # 判断测试用例列表中预期结果集是否为列表 print('debug', self.params_to_compare) list_params_to_compare = eval( self.params_to_compare) # 将数据库中的unicode编码数据转换为列表 if set(list_params_to_compare).issubset( set(temp_result_list_response)): # 判断集合包含关系 result = { 'code': '0000', 'message': '参数完整性比较一致', 'data': [] } self.db.op_sql( "UPDATE case_interface set params_actual=\"%s\"," "result_params_compare =%s where id =%s" % (temp_result_list_response, 1, self.id_case)) else: result = { 'code': '3001', 'message': '实际结果中元素不都在预期结果中', 'data': [] } self.db.op_sql( "UPDATE case_interface set params_actual=\"%s\"," "result_params_compare =%s where id =%s" % (temp_result_list_response, 0, self.id_case)) else: result = { 'code': '4001', 'message': '用例中待比较参数集错误', 'data': self.params_to_compare } else: result = { 'code': '2001', 'message': '调用__recur_params__方法返回错误', 'data': self.params_to_compare } self.db.op_sql( "UPDATE case_interface set result_params_compare =%s where id =%s" % (2, self.id_case)) except Exception as e: result = {'code': '9999', 'message': '参数完整性比较异常', 'data': []} self.db.op_sql( "UPDATE case_interface set result_params_compare =%s where id =%s" % (9, self.id_case)) MyLog.error(e) return result
'code'] == '0000' elif child_level_check in [2]: # 执行功能测试,待开发 pass elif child_level_check in [3]: # 执行结构完整性检查,待开发 pass else: allure.attach('用例编号:%s|接口名称:%s|检查级别错误:%s\n' % (id_case, name_interface, child_level_check)) assert True elif len(result_http_respones['data']) == 0: allure.attach('接口名称: %s|信息错误:获取用例数据为空,请检查用例\n' % name_interface) assert False else: allure.attach( '接口名称: %s|信息错误:获取用例数据失败|错误信息: %s\n' % (name_interface, data_case_interface['message'])) assert False # print('#####################结束执行接口:%s#################### \n' % name_interface) else: MyLog.error('错误信息:待执行接口获取失败|错误信息:%s' % module_execute['message']) if __name__ == '__main__': import os pytest.main(['-s', '-q', 'pytest_run.py', '--alluredir', './result/']) os.system('allure serve ./result/')
print( '#####################结束执行接口:%s#################### \n' % temp_name_interface) else: print('错误信息:待执行接口获取失败|错误信息:%s' % module_execute['message']) elif value_input == '1': print('你输入的是:1|导出测试用例结果,请注意查看目录:%s' % (config.src_path + '\\report')) name_export = base_db.select_one( "SELECT value_config from config_total " "WHERE `status` =1 AND key_config = 'name_export'" ) # 获取导出的接口数据元组 print(name_export) if name_export['code'] == '0000' and len( name_export['data']['value_config']) != 0: #判断查询结果 temp_export = eval( name_export['data']['value_config']) #获取查询数据,并将其转化为字典 test_analyse_data = AnalyseData() result_export = test_analyse_data.export2excel( temp_export) #导出测试结果 print(result_export['message']) print("导出失败接口列表: %s\n" % result_export['data']) else: print('请检查配置表数据正确性,当前值为:%s \n' % name_export['data']) except Exception as e: print('系统出现异常:%s ' % e) MyLog.error(e) input('Press Enter to exit...')