def __init__(self, excel_path, sheet=0): ''' 指定默认参数文件、表格、构造标识 :param excel: Excel文件路径(xls格式) :param sheet: 默认表格0 ''' excel_extension = str(os.path.splitext(excel_path)[1]) try: if os.path.exists(excel_path): if excel_extension.lower() not in [".xls"]: raise DotTypeError else: raise FileNotFoundError self.excel_path = excel_path init_workbook = open_workbook(excel_path, formatting_info=True) sheet_reader = init_workbook.sheet_by_index(sheet) self.row_count = sheet_reader.nrows self.column_count = sheet_reader.ncols self.workbook = copy(init_workbook) logger.info('[Initial]:当前准备同步的EXCEL文件为:{}'.format(excel_path)) self.w = self.workbook.get_sheet(sheet) logger.info('当前Sheet表格限定为:{}'.format(sheet)) except DotTypeError: logger.exception( '当前不支持文件扩展名"{}", 请指定xls格式的表格文件.'.format(excel_extension)) except FileNotFoundError: logger.exception('非法EXCEL文件路径!~ "{}"'.format(excel_path))
def dsl_search(self, es_index, es_dsl): """ ELK DSL查询 :param es_index: ES索引 :param es_dsl: ES查询语句 :return: """ if not isinstance(es_dsl, dict): logger.exception("【ELK】DSL查询语句类型错误,请用字典形式指定!") else: es_res = self._session.post( url= 'http://esk.qa.com/api/console/proxy?path={}%2F_search%3Ftrack_total_hits%3Dtrue&method=POST' .format(str(es_index)), data=json.dumps(es_dsl, ensure_ascii=False), headers={ "kbn-xsrf": "", "Cookie": "{}".format(self.cookies_str), 'Content-Type': 'application/json' }) if es_res.status_code == 200: return es_res else: logger.error( "【ELK】查询失败,执行的DSL语句为:\n{}\n\n异常响应信息如下:\n{}".format( json.dumps(es_dsl, ensure_ascii=False, indent=2), json.dumps(es_res.json(), ensure_ascii=False, indent=2))) sys.exit(1)
def check_match_urlpath(self): """ 检测Swagger接口文档与接口抓包文档中的UrlPath是否映射匹配 :return: """ try: case_doc_df_count = self.case_doc_df.shape[0] capture_doc_df_count = self.capture_doc_df.shape[0] if case_doc_df_count == 0: logger.warning( "[WARNING]:检测到Swagger接口文档中无任何映射匹配的UrlPath,请检查相关接口文档是否符合需求或手动追加!" ) return False if case_doc_df_count < capture_doc_df_count: swagger_doc_less_set = set([ str(i).strip() for i in self.capture_doc_df["CID"].values.tolist() ]) - set([ str(i).strip() for i in self.case_doc_df["UrlPath"].values.tolist() ]) logger.warning( "[WARNING]:检测到Swagger接口文档中缺少映射匹配的UrlPath,检测结果:{},请检查相关接口文档是否符合需求或手动追加!" .format(swagger_doc_less_set)) return False if case_doc_df_count == capture_doc_df_count: logger.info( "[Success]:Swagger接口文档与接口抓包文档中UrlPath映射匹配规则检测通过,二者存在数量相等且映射匹配的UrlPath." ) return True except Exception: logger.exception( "[Exception]:检测Swagger接口文档与接口抓包文档进行UrlPath映射匹配规则过程中发生异常,请检查!") return False
def untar(self, tarname, dstpath=OUTPUT_PATH): ''' 将指定tar包压缩文件解压缩到指定文件夹,并删除源tar包压缩文件 :param tarname: 待解压tar包压缩文件(需指定绝对路径) :param dstpath: 指定解压路径(层级结构,默认解压缩路径为OUTPUT_PATH文件目录) :return dstpath:返回解压缩路径 ''' try: initname = re.split(r'[\\|/]', tarname)[-1] dot = os.path.splitext(initname)[1] comtype = dot[1:] if os.path.isfile(tarname) and os.path.exists(tarname): if dot in [r'.gz', r'.bz2', r'.xz']: tarhandler = tarfile.open(tarname, "r:{}".format(comtype)) for file in tarhandler.getnames(): logger.info('文件"{0}"开始{1}解压缩提取.'.format(file, comtype)) tarhandler.extractall(dstpath) logger.info('压缩文件"{0}"已{1}解压缩成功, 解压路径为:"{2}".'.format( initname, comtype, dstpath)) tarhandler.close() os.remove(tarname) logger.info('压缩文件"{}"已物理删除.'.format(initname)) return dstpath else: raise DotTypeError else: raise FileNotFoundError except FileNotFoundError: logger.exception('文件不存在或其路径非法, 请检查参数路径(其中压缩文件需指定绝对路径).') except DotTypeError: logger.exception( '非法压缩文件后缀名"{}", 请指定".tar.gz/.tar.bz2/.tar.xz"中任意后缀名的压缩文件名称.'. format(dot))
def rebase_build_info(self, job_name): """ 获取指定项目名称的自定义构建信息 :param job_name: 构建项目名称 :return: 构建信息自定义响应体 """ response_list = [] try: job_set = self.get_job_info(job_name) if job_set['lastBuild'] is not None: response_list.append( dict( ActionJob=job_set['displayName'], LastNumber=job_set['lastBuild']['number'], Building=self.get_job_build_info( job_set['displayName'], job_set['lastBuild']['number'])['building'], Result=self.get_job_build_info( job_set['displayName'], job_set['lastBuild']['number'])['result'], Time=trans_timestamp( self.get_job_build_info( job_set['displayName'], job_set['lastBuild']['number'])['timestamp']))) else: response_list.append( dict(ActionJob=job_set['displayName'], LastBuild="No latest build job info now.")) return response_list except Exception: logger.exception( '通过构建项目名称"{}"查看其自定义构建信息过程中发生异常,请检查!'.format(job_name))
def check_exist_urlpath(self): """ 检测接口抓包文档在Swagger接口文档中是否存在匹配的UrlPath :return: """ try: if self.capture_doc_df["CID"].shape[ 0] == 0 or self.capture_doc_cid_check == []: logger.warning( "[WARNING]:接口抓包文档中UrlPath当前无任何填充数据,请首先完成接口抓包工作!") sys.exit(1) if self.case_doc_df["UrlPath"].shape[0] == 0: logger.warning( "[WARNING]:接口抓包文档中UrlPath在Swagger接口文档中未匹配到任何数据,请检查接口抓包文档和Swagger接口文档是否符合需求!" ) return False if self.case_doc_df["UrlPath"].shape[ 0] != 0 and self.capture_doc_df["CID"].shape[0] != 0: logger.info( "[Success]:Swagger接口文档及接口抓包文档中UrlPath是否存在匹配数据检测通过,二者UrlPath存在匹配数据." ) return True except Exception: logger.exception( "[Exception]:检测接口抓包文档中UrlPath在Swagger接口文档中是否存在匹配数据过程中发生异常,请检查!" ) return False
def generate(self, test_case_file, sep=r'|', encoding='utf-8'): """ 生成测试用例文件(当前支持Excel文件[xls/xlsx]及文本文件[csv/txt]) :param test_case_file: 测试用例文件路径 :param sep: 文件分隔符,默认"|"。 :param encoding: 文件编码格式。 :return: """ logger.info("[Initial]:开始自动评估测试用例生成条件......") file_extend = str(os.path.splitext(test_case_file)[-1]).lower() try: test_case_df = self.load_test_case if file_extend not in [".csv", ".txt", ".xls", ".xlsx"]: logger.warning( "[WARNING]:自动生成的测试用例文件扩展名当前仅支持[csv、txt、xls、xlsx],请检查!") sys.exit(1) if file_extend in ['.xls', '.xlsx']: logger.info( "[Loading]:开始自动生成{}格式测试用例文件......".format(file_extend)) test_case_df.to_excel(test_case_file, index=False) if file_extend in ['.csv', '.txt']: logger.info( "[Loading]:开始自动生成{}格式测试用例文件......".format(file_extend)) test_case_df.to_csv(test_case_file, sep=sep, index=False, header=True, encoding=encoding) logger.info('[Done]:{}格式测试用例文件已经成功自动生成,路径为"{}".'.format( file_extend, test_case_file)) except Exception: logger.exception( "[Exception]: {}格式测试用例文件自动生成过程中发生异常,请检查!".format(file_extend)) sys.exit(1)
def __init__(self, excel_path, sheet=0): ''' 指定默认参数文件、表格、构造标识 :param excel: Excel文件路径(xlsx格式) :param sheet: 默认表格0 ''' excel_extension = str(os.path.splitext(excel_path)[1]) try: if os.path.exists(excel_path): if excel_extension.lower() not in [".xlsx"]: raise DotTypeError else: raise FileNotFoundError self.excel_path = excel_path self.init_workbook = load_workbook(excel_path) specify_sheet = self.init_workbook.sheetnames[sheet] self.sheet_reader = self.init_workbook[specify_sheet] self.row_count = self.sheet_reader.max_row self.column_count = self.sheet_reader.max_column logger.info('[Initial]:当前准备同步的EXCEL文件为:{}'.format(excel_path)) logger.info('当前Sheet表格限定为:{}'.format(sheet)) except DotTypeError: logger.exception( '当前不支持文件扩展名"{}", 请指定xlsx格式的表格文件.'.format(excel_extension)) except FileNotFoundError: logger.exception('非法EXCEL文件路径!~ "{}"'.format(excel_path))
def send(self, msgtype): """ 发送钉钉机器人消息提醒 :param msgtype: 消息提醒类型 :return: """ try: if msgtype not in [ 'text', 'link', 'markdown', 'actionCard', 'feedCard' ]: logger.warning( '[WARNING]:检测到非法消息类型"{}",当前仅支持text、link、markdown、actionCard、feedCard,请重新指定!' .format(msgtype)) sys.exit(1) url = "https://oapi.dingtalk.com/robot/send?access_token={}×tamp={}&sign={}".format( self.token, self.timestamp, self.get_sign) headers = {'Content-Type': 'application/json'} response = requests.request("POST", url, headers=headers, data=self.generate_msg(msgtype)) result = response.json() if result.get("errcode") == 0 and result.get("errmsg") == 'ok': logger.info("[Done]:钉钉机器人消息提醒成功.") else: logger.warning( "[WARNING]:钉钉机器人消息提醒失败,接口响应为【{}】,开始重试...".format(result)) sys.exit(1) except Exception: logger.exception("[Exception]:发送钉钉机器人消息提醒过程中发生异常,请检查!") sys.exit(1)
def check_match_urlpath(self): """ 检测接口抓包文档与映射接口文档中匹配的UrlPath是否存在一一映射匹配关系 :return: """ try: case_doc_df_count = self.case_doc_df.shape[0] capture_doc_df_count = self.capture_doc_cid_check.__len__() if case_doc_df_count < capture_doc_df_count: swagger_doc_less_set = set([ str(i).strip() for i in self.capture_doc_df["CID"].values.tolist() ]) - set([ str(i).strip() for i in self.case_doc_df["UrlPath"].values.tolist() ]) logger.warning( "[WARNING]:检测到映射接口文档中缺少接口抓包文档中映射匹配的UrlPath,检测结果:{},请检查相关接口文档是否符合需求或手动追加!" .format(swagger_doc_less_set)) return False if case_doc_df_count == capture_doc_df_count: logger.info( "[Success]:映射接口文档与接口抓包文档中UrlPath一一映射匹配关系检测通过,二者存在一一映射匹配的UrlPath." ) return True except Exception: logger.exception( "[Exception]:检测映射接口文档与接口抓包文档进行UrlPath一一映射匹配关系过程中发生异常,请检查!") return False
def check_duplicate_urlpath(self): """ 检测映射接口文档中匹配的UrlPath是否存在重复值 :return: """ pass_flag = False try: if self.check_exist_urlpath is True: case_doc_urlpath_veriry = { i: j for i, j in dict( Counter([ str(i).strip() for i in self.case_doc_df["UrlPath"].values.tolist() ])).items() if j > 1 } if case_doc_urlpath_veriry == {}: logger.info( "[Success]:映射接口文档中匹配的UrlPath是否存在重复值检测通过,其匹配的UrlPath均唯一." ) return True if case_doc_urlpath_veriry != {}: logger.warning( '[WARNING]:检测到映射接口文档中存在重复的UrlPath,检测结果:{},请仔细核对并明确需求!'. format(case_doc_urlpath_veriry)) pass_flag = False return pass_flag else: logger.error( "[Fail]:Swagger接口文档与接口抓包文档进行UrlPath数据匹配检测失败,请仔细检查相关文档数据!") sys.exit(1) except Exception: logger.exception( "[Exception]:检测映射接口文档中匹配的UrlPath是否存在重复值过程中发生异常,请检查!") return False
def unzip(self, zipname, dstpath=OUTPUT_PATH): ''' 将指定zip文件解压缩到指定文件夹,并删除源zip压缩文件 :param zipname: 待解压zip压缩文件(需指定绝对路径) :param dstpath: 指定解压路径(层级结构,默认解压缩路径为OUTPUT_PATH文件目录) :return dstpath:返回解压缩路径 ''' try: initname = re.split(r'[\\|/]', zipname)[-1] dot = os.path.splitext(initname)[1] if os.path.isfile(zipname) and os.path.exists(zipname): if dot == r'.zip': ziphandler = zipfile.ZipFile(zipname, 'r') for file in ziphandler.namelist(): logger.info('文件"{}"开始unzip解压缩提取.'.format(file)) ziphandler.extractall(dstpath) logger.info('压缩文件"{0}"已unzip解压缩成功, 解压路径为:"{1}".'.format( initname, dstpath)) ziphandler.close() os.remove(zipname) logger.info('压缩文件"{}"已物理删除.'.format(initname)) return dstpath else: raise DotTypeError else: raise FileNotFoundError except FileNotFoundError: logger.exception('文件不存在或其路径非法, 请检查参数路径(其中zip压缩文件需指定绝对路径).') except DotTypeError: logger.exception('非法压缩文件后缀名"{}", 请指定".zip"后缀名的压缩文件名称.'.format(dot))
def query_file_df(self, script_file, index_col=None, chunksize=None): """ 通过sqlalchemy并使用read_sql_query方式执行脚本文件并返回结果 :param script_file: 脚本文件 :param index_col: 将指定列作为索引 :param chunksize: 缓存区大小 :return: """ script_string = None try: if os.path.exists(script_file): with open(script_file, mode=r'r', encoding='utf-8') as script: script_string = script.read() result = pd.read_sql_query(script_string, con=self.mysql_engine, index_col=index_col, chunksize=chunksize) return result else: raise FileNotFoundError except FileNotFoundError: logger.exception( '[Exception]:MySQL脚本文件"{}"当前并不存在'.format(script_file)) except Exception: logger.exception( "[Exception]:执行MySQL脚本过程中发生异常,请检查!~ 脚本为:【{}】".format( script_string))
def load_test_case(self): """ 依据swagger接口文档及接口抓包文档生成测试用例 :return: """ try: if self.check_duplicate_urlpath is True: if self.check_match_urlpath is True: self.case_doc_df["Platform"] = [ str(platform).strip().capitalize() for platform in self.capture_doc_df["Platform"].values.tolist() ] self.case_doc_df["Level"] = [ str(level).strip().upper() for level in self.capture_doc_df["Level"].values.tolist() ] self.case_doc_df["Active"] = True self.case_doc_df["Group"] = self.capture_doc_df[ "Group"].values.tolist() self.case_doc_df["Order"] = self.capture_doc_df[ "Order"].values.tolist() self.case_doc_df["RequestPath"] = self.capture_doc_df[ "Path"].values.tolist() self.case_doc_df["RequestHeader"] = self.capture_doc_df[ "Header"].values.tolist() self.case_doc_df["RequestParam"] = self.capture_doc_df[ "Param"].values.tolist() self.case_doc_df["RequestData"] = self.capture_doc_df[ "Data"].values.tolist() self.case_doc_df["RequestFile"] = self.capture_doc_df[ "File"].values.tolist() self.case_doc_df["DependencyInfo"] = self.capture_doc_df[ "Dependency"].values.tolist() self.case_doc_df["AssertInfo"] = self.capture_doc_df[ "Assert"].values.tolist() self.case_doc_df = self.case_doc_df.sort_values( by="Order", ascending=True) self.case_doc_df = self.case_doc_df.reset_index( drop=True).reset_index().rename( columns={"index": "ID"}) self.case_doc_df["ID"] = self.case_doc_df["ID"].apply( lambda x: "TC_{}".format(x + 1)) return self.case_doc_df else: logger.warning( "[WARNING]:Swagger接口文档与接口抓包文档中UrlPath映射匹配规则检测未通过,请查看相关检测结果!" ) sys.exit(1) else: logger.warning( "[WARNING]:Swagger接口文档或接口抓包文档中各自UrlPath列是否存在重复值检测未通过,请查看相关检测结果!" ) sys.exit(1) except Exception: logger.exception( "[Exception]:依据Swagger接口文档及接口抓包文档自动生成测试用例过程中发生异常,请检查!") sys.exit(1)
def get_job_info_by_regex(self, pattern): """ 正则表达式方式获取构建项目信息 :param pattern: 构建项目名称(正则表达式) :return: """ try: info_regex = self.session.get_job_info_regex(pattern=pattern) return info_regex except Exception: logger.exception('通过正则表达式"{}"查看匹配构建项目过程中发生异常,请检查!'.format(pattern))
def close_session(self): """ 关闭连接会话 :return: """ try: self.session.close() logger.exception("[Done]:".format(self.dbtype.upper())) except Exception: logger.exception("[Exception]:关闭{}会话实例过程中发生异常,请检查!".format( self.dbtype.upper()))
def create_session(self): """ 创建数据库连接会话 :return session:会话实例 :return: """ try: if self.dbtype == r'mysql': mysqlParam = YamlConfig(config=APPLICATION_CONFIG_FILE).get( "mysql", 1).get(self.env) self.session = pymysql.connect(host=mysqlParam['host'], user=mysqlParam['username'], password=str( mysqlParam['password']), port=mysqlParam['port'], database=str(self.dbname)) return self.session elif self.dbtype == r'redis': redisParam = YamlConfig(config=APPLICATION_CONFIG_FILE).get( 'redis', 1)[self.env] pool = redis.ConnectionPool( host=redisParam['host'], port=redisParam['port'], db=self.dbname, decode_responses=True, ) self.session = redis.StrictRedis(connection_pool=pool, charset='utf-8') return self.session elif self.dbtype == r'mongodb': mongoParam = YamlConfig(config=APPLICATION_CONFIG_FILE).get( 'mongodb', 1)[self.env] self.session = MongoClient(host=mongoParam['host'], port=mongoParam['port']) return self.session else: raise DatabaseTypeError except InternalError: logger.exception('[Exception]:当前指定的MySQL数据库"{}"并不存在.'.format( self.dbname)) except DatabaseTypeError: logger.exception('[Exception]:数据库类型{}不支持创建连接会话.'.format( self.dbtype.upper())) except ConnectionError: logger.exception('[Exception]:Redis会话连接错误, 请检查连接会话参数和当前网络状况.') except ResponseError: logger.exception( '[Exception]:Redis数据库索引值"{}"非法, 请输入合法的数据库索引(int类型标识).'.format( self.dbname)) except Exception: logger.exception('[Exception]:创建{}数据库会话实例过程中发生异常,请检查!'.format( self.dbtype.upper()))
def query_string(self, script_str): """ 通过sqlalchemy并使用engine方式执行脚本(字符串)并返回结果 :param script_str: 脚本字符串 :return: """ try: result = self.mysql_engine.execute(script_str).fetchall() return result except Exception: logger.exception( "[Exception]:执行MySQL脚本过程中发生异常,请检查!~ 脚本为:【{}】".format( script_str))
def stop_job_latest_build(self, job_name): """ 停止匹配正则表达式的构建项目的最近构建任务 :param job_name: 构建项目名称 :return: """ try: lastNumber = self.rebase_build_info( job_name=job_name)[0]['LastNumber'] self.session.stop_build(name=job_name, number=lastNumber) except Exception: logger.exception( '停止匹配正则表达式"{}"的构建项目的最近构建任务过程中发生异常,请检查!'.format(job_name))
def __init__(self, url, username, password): """ 初始化Jenkins连接信息 :param url: Jenkins地址 :param username: 登录用户名 :param password: 登录密码 """ try: self.session = Jenkins(url=url, username=username, password=password) except Exception: logger.exception('初始化Jenkins连接过程中发生异常,请检查!')
def decrypt(self): """ 解密方法 :return: 解密响应体字串 """ try: response_hex_str = encrypt.a2b_hex(self.response_str) response_base64_str = encrypt.BASE64(response_hex_str).decode('utf-8') response_debase64_str = encrypt.BASE64_Decrypt(response_base64_str.encode('utf-8')) decrypt_response_str = encrypt.AES_Decrypt1(encrypt_str=response_debase64_str, key=encrypt.add_16(self.key)) return decrypt_response_str except Exception: logger.exception("[Exception]:解密接口响应体加密字串过程中发生异常,请检查!") sys.exit(1)
def get_job_build_info(self, job_name, build_number): """ 通过构建项目名称及构建任务ID查看构建信息 :param job_name: 构建项目名称 :param build_number: 构建ID :return: """ try: result = self.session.get_build_info(name=job_name, number=build_number) return result except Exception: logger.exception('通过构建项目名称"{}"和构建ID"{}"查看构建信息过程中发生异常,请检查!'.format( job_name, build_number))
def __init__(self, test_case_file): """ 初始化用例文件DataFrame。 :param test_case_file: 用例文件绝对路径 """ file_extension = os.path.splitext(str(test_case_file))[-1] try: if not os.path.exists(test_case_file): raise FileNotFoundError if file_extension == "": logger.exception("未检测到包含用例文件扩展名的合法路径,请仔细检查!") if str(file_extension).lower() in ['.xls', '.xlsx']: self.test_case_df = pd.read_excel(test_case_file).set_index( "ID", drop=False).fillna("") elif str(file_extension).lower() in ['.csv', '.txt']: self.test_case_df = pd.read_csv( test_case_file, sep=r',').set_index("ID", drop=False).fillna("") else: raise DotTypeError except DotTypeError: logger.exception( '非法文件扩展名"{}", 当前仅支持xls、xlsx、csv、txt用例文件扩展名.'.format( file_extension)) except FileNotFoundError: logger.exception('当前用例文件"{}"并不存在,请检查路径!'.format(test_case_file)) except Exception: logger.exception("初始化用例DataFrame过程中发生异常,请检查!")
def clear_result(cls): """ 清空Allure测试结果json文件。 """ try: if os.listdir(ALLURE_RESULT) != list(): time.sleep(1) shutil.rmtree(ALLURE_RESULT) os.mkdir(ALLURE_RESULT) logger.info("[Success]:已经成功清空Allure历史测试结果.") else: logger.info("当前暂无Allure历史测试结果,无需清除操作!") except Exception: logger.exception("[Exception]:清空Allure历史测试结果过程中发生异常,请检查!")
def initial_allure(cls): """ 初始化Allure :return: """ try: logger.info('[Initial]:开始初始化Allure......') cls.clear_result() if os.path.exists(ALLURE_REPORT): cls.sync_history() cls.sync_environment() cls.sync_categories() logger.info("[Done]:已经成功初始化Allure.") except Exception: logger.exception("[Exception]:初始化Allure过程中发生异常,请检查!")
def check_duplicate_urlpath(self): """ 检查Swagger接口文档及接口抓包文档中是否存在重复的UrlPath. :return: """ pass_flag = False try: if self.check_empty_urlpath is True: swagger_doc_urlpath_veriry = { i: j for i, j in dict( Counter([ str(i).strip() for i in self.swagger_doc_df["UrlPath"].values.tolist() ])).items() if j > 1 } capture_doc_urlpath_veriry = { i: j for i, j in dict( Counter([ str(i).strip() for i in self.capture_doc_df["CID"].values.tolist() ])).items() if j > 1 } if swagger_doc_urlpath_veriry == {} and capture_doc_urlpath_veriry == {}: logger.info( "[Success]:Swagger接口文档或接口抓包文档中各自UrlPath列是否存在重复值检测通过,二者各自UrlPath列均无重复值." ) return True if swagger_doc_urlpath_veriry != {}: logger.warning( '[WARNING]:检测到Swagger接口文档中存在重复的UrlPath,检测结果:{},请仔细核对并明确需求!' .format(swagger_doc_urlpath_veriry)) pass_flag = False if capture_doc_urlpath_veriry != {}: logger.warning( '[WARNING]:检测到接口抓包文档中存在重复的UrlPath,检测结果:{},请仔细核对并明确需求!'. format(capture_doc_urlpath_veriry)) pass_flag = False return pass_flag else: logger.warning("[WARNING]:请先正常初始化Swagger接口文档和接口抓包文档!") sys.exit(1) except Exception: logger.exception( "[Exception]:检测Swagger接口文档或接口抓包文档中各自UrlPath列是否存在重复值过程中发生异常,请检查!" ) return False
def get_sign(self): """ 生成钉钉机器人签名字串 :return: """ try: secret_enc = self.secret.encode('utf-8') string_to_sign = '{}\n{}'.format(self.timestamp, self.secret) string_to_sign_enc = string_to_sign.encode('utf-8') hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest() sign = urllib.parse.quote_plus(base64.b64encode(hmac_code)) return sign except Exception: logger.exception("[Exception]:生成钉钉机器人签名字串过程中发生异常,请检查!")
def get_job_info(self, job_name): """ 获取构建项目信息 :param job_name: 构建项目名称 :return: """ try: if self.session.job_exists(name=job_name): info = self.session.get_job_info(name=job_name) return info else: logger.warning( '[WARNING]: Jenkins构建项目"{}"并不存在,请检查!'.format(job_name)) sys.exit(1) except Exception: logger.exception('查看Jenkins构建项目"{}"过程中发生异常,请检查!'.format(job_name))
def generate_data(self): ''' 返回构造的sheet表单内数据 :return: ''' try: if self.data_type: title = self.r.row_values(0) for col in range(1, self.r.nrows): self._data.append(dict(zip(title, self.r.row_values(col)))) else: for col in range(0, self.r.nrows): self._data.append(self.r.row_values(col)) logger.info("[Success]:当前Excel文件已成功完成数据生成!") return self._data except Exception: logger.exception("初始化Excel文件数据过程中发生异常,请检查!")
def generate_report(cls): """ 根据json结果文件自动生成Allure测试报告。 """ try: if cls.check_result() is True: command = "allure generate {0} -o {1} --clean".format(ALLURE_RESULT, ALLURE_REPORT) time.sleep(1) logger.info('开始执行Allure测试报告生成命令:"{}"'.format(command)) run_command(command) logger.info("[Done]:已经成功生成Allure测试报告.") else: logger.warning("[Warning]:由于未检测到Allure测试结果json文件,停止生成Allure测试报告!") except CalledProcessError: logger.exception("[Exception]:Allure测试报告生成命令执行失败!") except Exception: logger.exception("[Exception]:生成Allure测试报告过程中发生异常,请检查!")