def send_IM(self, pass_rate, total, _pass, failure, error, merge_report_file_name): """ IM report 发送到IM群 如果需要自定义内容,可实现_custom_IM_body方法 """ LogUtil.info(u"[IM SEND BEGIN] 开始发送IM 群通知。。。") IM_body, pass_rate = IM_report.format_report_for_temporary_test( pass_rate=pass_rate, total_case=total, pass_case=_pass, failure_case=failure, error_case=error, ) # 自定义内容 custom_IM_body = self._custom_IM_body() final_IM_body = u"{}\n详细报告 :<a href=http://{}/auto_reports/{}/{}>Report Link</a> \n{}".format( IM_body, tomcat_server, self.project_name, merge_report_file_name, custom_IM_body) title_time = time.strftime("%Y-%m-%d_%H:%M", time.localtime()) msg_title = u"{} 自动化测试报告_{} - 通过率 : {} %".format( self.project_name.upper(), title_time, pass_rate) self.IM_client.send_msg_to_group(msg_title, final_IM_body, self.group_id) for receiver in self.report_receiver_list: self.IM_client.send_msg_to_person(msg_title, final_IM_body, receiver)
def _send_IM(self): """ IM report 发送到IM群 如果需要自定义内容,可实现_custom_IM_body方法 """ LogUtil.info(u"[IM SEND BEGIN] 开始发送IM 群通知。。。") IM_body, pass_rate = IM_report.format_simple_summary( self.unittest_results) # 当前服务请求接口数量 covered_api_counter = self.__counter_current_project_covered_api() if covered_api_counter: IM_body += "\ncovered_api_counter : {}\n".format( covered_api_counter) # 自定义内容 custom_IM_body = self._custom_IM_body() final_IM_body = u"{}\n详细报告 :<a href=http://{}/auto_reports/{}/{}>Report Link</a> \n{}".format( IM_body, tomcat_server, self.project_name, self.report_file_name, custom_IM_body) title_time = time.strftime("%Y-%m-%d_%H:%M", time.localtime()) msg_title = u"{} 自动化测试报告_{} - 通过率 : {} %".format( self.project_name.upper(), title_time, pass_rate) self.IM_client.bot_join_group(self.group_id) self.IM_client.send_msg_to_group(msg_title, final_IM_body, self.group_id) for receiver in self.report_receiver_list: self.IM_client.send_msg_to_person(msg_title, final_IM_body, receiver)
def _print_cover_request_url_set(self, request_url_set): LogUtil.info( u"\n-----------------------------------------------------------------------" ) LogUtil.info(u"【URL 覆盖】当前项目【{}】 覆盖的url,接口如下: ".format( self.project_name)) print('\n'.join(request_url_set))
def _post(self): """ 后处理 用于处理数据,结果处理,展示等 这里暂时不留钩子 """ # 拷贝到远程 if self.is_scp_to_remote: self._scp_to_remote() else: LogUtil.info(u"[REMOTE] 指定不拷贝到远程!本地文件名不带时间戳。")
def get_email(): ''' 随机生成一个可用的邮箱 :return: ''' randNumb = random.randint(1, 9999999) mail = "auto.mail.{}@bytedance.com".format(randNumb) LogUtil.info(u"使用随机生成的email : " + str(mail)) return mail
def __generate_local_report_file_path(self): """ 生成本地文件路径,这里用的根路径加report """ local_report_file_full_path = os.path.abspath( os.path.join(test_env_config.ROOT_DIR, "report", self.report_file_name)) LogUtil.info("Report_name=" + self.report_file_name) LogUtil.info(u"报告存放位置: \n" + local_report_file_full_path) # 确定生成报告的本地全路径 self.local_report_file_full_path = local_report_file_full_path
def _act(self): """ 执行case,产生结果 """ self._generate_var() LogUtil.info(u"[RUN BEGIN] 结果输出到本地路径: {}".format( self.local_report_file_full_path)) local_out_stream = open(self.local_report_file_full_path, 'wb') runner = HTMLTestRunner.HTMLTestRunner( stream=local_out_stream, title=self.report_title, description=self.report_description) self.unittest_results = runner.run(self.suite()) LogUtil.info(u"[RUN END] 结果输出到本地路径: {}".format( self.local_report_file_full_path))
def get_name(sale_id=None): ''' 随机生成一个名称,有Auto关键字 :param sale_id: 不填写没东西,如果填写了虚拟人员id,会拼写虚拟人员中文名 :return: ''' ticks = str(int(time.time())) # ran = str(random.randint(0, 50000)) if sale_id: name = people_dict.get_name_by_id(sale_id) else: name = u"名字" name = u"Auto-{}{}".format(name, ticks) LogUtil.info(u"随机生成的名称: {}".format(name)) return name
def post_after_merge(self, pass_rate, total, _pass, failure, error, merge_report_file_name): """ 合并后发送IM消息 """ # 拷贝到远程 if self.is_scp_to_remote: self.scp_merge_file_to_remote(merge_report_file_name) else: LogUtil.info(u"[REMOTE] 指定不拷贝到远程!本地文件名不带时间戳。") # 发送IM通知 if self.is_send_IM: self.send_IM(pass_rate=pass_rate, total=total, _pass=_pass, failure=failure, error=error, merge_report_file_name=merge_report_file_name)
def get_number_serial(length=None): ''' 随机生成一个数字序列号 返回 str 至少3位 ''' if length == None: return str(random.randint(19999999999999, 99999999999999)) elif length > 3: number_of_zero = length - 1 start_serial = "1{}".format("".rjust(number_of_zero, str('0'))) start_long = long(start_serial) end_serial = "1{}".format("".rjust(length, str('0'))) end_long = long(end_serial) - 1 randNumb = random.randint(start_long, end_long) else: raise Exception(u'[ERROR]目前只支持三维以上随机数生成!!!') LogUtil.info(u"使用随机生成的长传数字: " + str(randNumb)) return randNumb
def _record_performance(start, request_obj): """ 记录性能相关,如果超过阈值,记录下来请求内容 """ end = datetime.datetime.now() diff_seconds = (end - start).total_seconds() LogUtil.info(u"-----------------------------------------------") LogUtil.info(u"【性能】请求花费时间 {} s ".format(diff_seconds)) LogUtil.info(u"-----------------------------------------------")
def _print_request_cost_info(self, request_list): LogUtil.info( u"\n-----------------------------------------------------------------------" ) LogUtil.info(u"【性能】接口耗时,超过 '{}' s 的接口请求如下: ".format( cached_data.time_cost_threshold)) if len(request_list) == 0: LogUtil.info(u"棒棒的,没有任何请求超过阈值!") request_url_dict = {} for request in request_list: request_url_dict[request.get('request').get('url')] = request.get( 'time') DataFormatter().print_dict_in_lines(request_url_dict)
def _scp_to_remote(self): """ 拷贝到远程 """ server_location = "{}:{}{}/".format( tomcat_server.split(":")[0], server_tomcat_dir, self.project_name) scp_command = 'scp {} {}'.format(self.local_report_file_full_path, server_location) LogUtil.info(u"[SCP REMOTE BEGIN] 拷贝到远程 命令: {}".format(scp_command)) os.system(scp_command) LogUtil.info( u"[SCP REMOTE END] 拷贝完成 remote tomcat server : \n {}".format( scp_command)) remote_url_head = "http://{}/auto_reports/{}/".format( tomcat_server, self.project_name, self.report_file_name) remote_full_path = remote_url_head + self.report_file_name LogUtil.info(u"远端服务器URL: {}".format(remote_full_path))
def _post(self): """ 后处理 用于处理数据,结果处理,展示等 这里暂时不留钩子 """ # 拷贝到远程 if self.is_scp_to_remote: self._scp_to_remote() else: LogUtil.info(u"[REMOTE] 指定不拷贝到远程!本地文件名不带时间戳。") # 发送IM通知 if self.is_send_IM: self._send_IM() else: LogUtil.info(u"[IM] 指定不发送IM") LogUtil.info(u"最后再次打印报告存放位置: \n" + self.local_report_file_full_path) # 最后打印一下,性能可能超标的请求 set self._print_request_cost_info(cached_data.request_list) self._print_cover_request_url_set(cached_data.request_path_set)
def scp_merge_file_to_remote(self, merge_report_file_name): """ 拷贝到远程 """ server_location = "{}:{}{}/".format( tomcat_server.split(":")[0], server_tomcat_dir, self.project_name) import os local_report_file_full_path = os.path.abspath( os.path.join(test_env_config.ROOT_DIR, "report", merge_report_file_name)) scp_command = 'scp {} {}'.format(local_report_file_full_path, server_location) LogUtil.info(u"[SCP REMOTE BEGIN] 拷贝到远程 命令: {}".format(scp_command)) import os os.system(scp_command) LogUtil.info( u"[SCP REMOTE END] 拷贝完成 remote tomcat server : \n {}".format( scp_command)) remote_url_head = "http://{}/auto_reports/{}/".format( tomcat_server, self.project_name, merge_report_file_name) remote_full_path = remote_url_head + merge_report_file_name LogUtil.info(u"远端服务器URL: {}".format(remote_full_path))
def rpc_request(self, func_name, params_body): """ 通过MS测试通用接口调用rpc接口获取结果 :param func_name: rpc方法名 不带括号,不带参数描述,支持下划线形式 如 query_a_b_c :param params_body: dict 该方法req的 params map :return: 调用成功的结果 """ LogUtil.info(u"-----------------【rpc Request】 ----------------") LogUtil.info(u" 基础参数 rpc_server_name: {}, address: {}".format(self.rpc_server_name, self.address)) payload = self._gen_rpc_payload(func_name, params_body) start = datetime.datetime.now() errno, data, msg = rpcOps().request_rpc_server_name_rpc(data=payload) end = datetime.datetime.now() diff_seconds = (end - start).total_seconds() LogUtil.info(u"-----------------【rpc Response】 ----------------") LogUtil.info(u" errno: {}, msg: {}, data: {}".format(errno, msg, data.__repr__().decode("unicode-escape"))) LogUtil.info(u"-----------------------------------------------") LogUtil.info(u"【性能】请求花费时间 {} s ".format(diff_seconds)) LogUtil.info(u"-----------------------------------------------") if errno: raise Exception(u"MS 接口调用结果错误,msg:{}".format(msg)) return data
def log_response_details(response_body): LogUtil.info( "-----[RESPONSE] details below : ----------------------------") LogUtil.info('Returned code: {}'.format(response_body.status_code)) if response_body.status_code != 200: LogUtil.info("[WARN]Return code is not 200!!!! but {} .".format( response_body.status_code)) err_msg = response_body.text try: json_body = response_body.json() s = str(json_body).replace('u\'', '\'') LogUtil.info(' Response: ') LogUtil.info(s.decode('unicode-escape')) err_msg = s.decode('unicode-escape') except Exception as e: LogUtil.error('Response raw data: ') LogUtil.exception(err_msg, e) LogUtil.error( u"\n【FATAL ERROR】检查请求细节是否出错,或者服务器是否有问题\n ---->> {}". format(err_msg)) else: try: json_body = response_body.json() s = str(json_body).replace('u\'', '\'') LogUtil.info(' Response: ') LogUtil.info(s.decode('unicode-escape')) except: LogUtil.info(u' Response raw data: \n{}'.format( response_body.text)) raise Exception("http请求的返回不是Json格式,检查服务器是否有问题") LogUtil.info( "------------------------------------------------------------------------" )
def log_request_details(url=None, headers=None, cookies=None, params=None, data=None, json_data=None, method=None): LogUtil.info( "-----[REQUEST] details below : ----------------------------") time_stamp = datetime.datetime.now() LogUtil.info(" Current time : {}".format( time_stamp.strftime('%Y.%m.%d-%H:%M:%S'))) LogUtil.info(" Request : {}".format(url)) if headers: LogUtil.info(" Headers : {}".format(headers)) if cookies: LogUtil.info(" Cookies : {}".format(cookies)) if params: try: LogUtil.info(" Parameters : {}".format( params.__repr__().decode("unicode-escape"))) except: LogUtil.info(" Parameters : {}".format(params)) if method: LogUtil.info(" Method : {}".format(method)) if data: try: LogUtil.info(" Payload : {}".format( data.__repr__().decode("unicode-escape"))) except: LogUtil.info(" Payload : {}".format(data)) if json_data: try: LogUtil.info(" Payload-json : {}".format( json_data.__repr__().decode("unicode-escape"))) except: LogUtil.info(" Payload-json : {}".format(json_data)) request_obj = {} request_obj['url'] = url request_obj['method'] = method request_obj['headers'] = headers request_obj['cookies'] = cookies request_obj['parameters'] = params request_obj['payload'] = data return request_obj
def merge_html(self, project_name, duration, merge_report_file_name, local=False): reports = {} index = 0 head_list = [] import os _re = project_name + '*html*' file_path = os.path.join(ROOT_DIR, "report", _re) for file in glob.glob(file_path): LogUtil.info(file) reports[index] = file index += 1 d = pq(filename=file, parser='html') if not d: continue head_list.append(d('div').filter(".heading")('.attribute').text().split()) start_time = min([head[2] for head in head_list]) + ' ' + min([head[3] for head in head_list]) duration = duration total = sum([int(head[13]) for head in head_list]) _pass = sum([int(head[17]) for head in head_list if head[15] == 'Pass']) # python 2.7 两个整数相除结果为整数,需要将至少一个转换为浮点数 pass_rate = round(float(_pass) / total * 100, 2) failure = sum(int(head[head.index('Failure') + 2]) for head in head_list if 'Failure' in head) error = sum(int(head[head.index('Error') + 2]) for head in head_list if 'Error' in head) message = u""" <html> <head> <body> {0} <div> {1} </div> </body> </head> </html>""" head = u""" <div class='heading'> <h1>{} API Automation Test Report</h1> <p class='attribute'><strong>Start Time:</strong> {}</p> <p class='attribute'><strong>Duration:</strong> {}min {}s</p> <p class='attribute'><strong>Pass Rate:</strong> {} %</p> <p class='attribute'><strong>Statistics:</strong> Total: {}; Pass: {}; Failure: {}; Error: {}; </p> <p class='description'></p> </div> """.format(project_name.upper(), start_time, int(duration)/60, int(duration)%60, pass_rate, total, _pass, failure, error) insert = [] for k, v in reports.items(): if not local: v = v.split('/')[-1] insert.append('<iframe id={} class="contentView" ' 'style="width: 100%;height: 400px;overflow: hidden;border: none;" ' 'src="{}"></iframe>'.format(k,v)) res = message.format(head, ''.join(insert)) # # 生成合并后的文件名 merge_full_path = os.path.join(ROOT_DIR, "report", merge_report_file_name) with open(merge_full_path, "w") as merge_file: merge_file.write(self.encode_utf8(res)) return start_time, pass_rate, total, _pass, failure, error