def get_test_report_excel_bytes_io(cls, report_id): test_report = cls.find_one({'_id': ObjectId(report_id)}) test_report = common.format_response_in_dic(test_report) bytes_io = BytesIO() workbook = xlsxwriter.Workbook(bytes_io, {'in_memory': True}) summary_sheet = workbook.add_worksheet(u'测试报告概览') detail_sheet = workbook.add_worksheet(u'测试报告详情') # 设置测试报告表头 format header_style = workbook.add_format() header_style.set_bg_color("#00CCFF") header_style.set_color("#FFFFFF") header_style.set_bold() header_style.set_border() # 测试报告概览表头 for index, value in enumerate(test_report_summary_map.values()): summary_sheet.write(0, index, value, header_style) # 设置测试报告概览每列宽度 [ ExcelHelper.ExcelSheetHelperFunctions.set_column_auto_width( summary_sheet, i) for i in range(len(test_report_summary_map.values())) ] # 测试报告概览数据 for index, value in enumerate(test_report_summary_map.keys()): summary_sheet.write(1, index, str(test_report.get(value, '(暂无此数据)'))) test_details = test_report['testDetail'] # 测试报告详情表头 for index, value in enumerate(test_report_detail_map.values()): detail_sheet.write(0, index, value, header_style) # 设置测试报告详情每列宽度 [ ExcelHelper.ExcelSheetHelperFunctions.set_column_auto_width( detail_sheet, i) for i in range(len(test_report_detail_map.values())) ] test_result_pass_style = workbook.add_format() test_result_pass_style.set_bg_color("#00ff44") test_result_pass_style.set_color("#FFFFFF") test_result_pass_style.set_bold() # test_result_pass_style.set_border() test_result_failed_style = workbook.add_format() test_result_failed_style.set_bg_color("#ff0026") test_result_failed_style.set_color("#FFFFFF") test_result_failed_style.set_bold() # test_result_failed_style.set_border() failed_curl_style = workbook.add_format() failed_curl_style.set_bg_color("#ffee00") # failed_curl_style.set_color("#FFFFFF") failed_curl_style.set_bold() # failed_curl_style.set_border() # 测试报告详情数据 for index, locator in enumerate(test_report_detail_map.keys()): locator = ast.literal_eval(locator) for col_index, detail in enumerate(test_details): if 'testConclusion' in str(locator): test_result = str(common.dict_get(detail, locator)) if '测试通过' in test_result: detail_sheet.write(col_index + 1, index, test_result, test_result_pass_style) else: detail_sheet.write(col_index + 1, index, test_result, test_result_failed_style) elif 'curl' in str(locator): test_result_status = str( common.dict_get(detail, ['status'])) if test_result_status == 'failed': detail_sheet.write( col_index + 1, index, str(common.dict_get(detail, locator)), failed_curl_style) else: detail_sheet.write( col_index + 1, index, str(common.dict_get(detail, locator))) else: detail_sheet.write(col_index + 1, index, str(common.dict_get(detail, locator))) workbook.close() bytes_io.seek(0) return bytes_io
def execute_single_case_test(self, test_case, is_debug=False): returned_data = dict() returned_data["_id"] = ObjectId(test_case["_id"]) returned_data["testConclusion"] = [] # 存储 处理过后的testCaseDetail returned_data["testCaseDetail"] = {} if not isinstance(test_case, dict): returned_data["status"] = 'failed' returned_data["testConclusion"].append({'resultType': test_conclusion.get(2), 'reason': "测试用例结构不正确"}) return returned_data def validate_test_case(case): required_key_list = ['route', 'requestMethod'] return all([required_key in case for required_key in required_key_list]) if not validate_test_case(test_case): returned_data["status"] = 'failed' returned_data["testConclusion"].append({'resultType': test_conclusion.get(2), 'reason': "接口必要参数不完整"}) return returned_data if test_case.get('isClearCookie'): self.session.cookies.clear() session = self.session request_url = None request_method = None request_headers = dict() request_body = None check_response_code = None check_spend_seconds = None check_response_body = None check_response_number = None set_global_vars = None # for example {'user': '******'} temp_suite_params = dict() new_temp_suite_params = dict() # 如果是debug测试用例,需要拿到临时Suite变量 if is_debug: if 'testSuiteId' in test_case and test_case["testSuiteId"]: temp_suite_params = get_temp_params_by_suite(test_case["testSuiteId"]) if temp_suite_params: self.global_vars.update(temp_suite_params) # 获取接口protocol if 'requestProtocol' in test_case and isinstance(test_case["requestProtocol"], str) \ and (test_case["requestProtocol"] == 'HTTP' or test_case["requestProtocol"] == 'HTTPS'): protocol = test_case["requestProtocol"] else: protocol = self.protocol # 获取接口domain if 'domain' in test_case and isinstance(test_case["domain"], str) and not test_case["domain"].strip() == '': domain = test_case["domain"] else: domain = self.domain # 替换domain中的${service} (如果存在) if 'service' in test_case and isinstance(test_case["service"], str) \ and not test_case["service"].strip() == '': domain = common.replace_global_var_for_str(init_var_str=domain, global_var_dic={'service': test_case["service"]}) # domain支持参数替换, 用于同一个用例组中调用不同domain的接口(不同环境的相同接口domain不同) domain = common.replace_global_var_for_str(init_var_str=domain, global_var_dic=self.global_vars) # 处理url protocol+domain+route route = common.replace_global_var_for_str(init_var_str=test_case['route'], global_var_dic=self.global_vars) \ if isinstance(test_case['route'], str) else test_case['route'] request_url = '%s://%s%s' % (protocol.lower(), domain, route) returned_data['testCaseDetail']['url'] = request_url # 获取method request_method = test_case['requestMethod'] returned_data['testCaseDetail']['requestMethod'] = request_method # 处理headers if 'headers' in test_case and test_case['headers'] not in ["", None, {}, {'': ''}]: if isinstance(test_case['headers'], list): for header in test_case['headers']: if not header['name'].strip() == '': header['value'] = func_var.resolve_func_var(init_func_var=header['value']) \ if isinstance(header['value'], str) else header['value'] request_headers[header['name']] = common.replace_global_var_for_str( init_var_str=header['value'], global_var_dic=self.global_vars) \ if isinstance(header['value'], str) else header['value'] else: raise TypeError('headers must be list!') request_headers = None if request_headers == {} else request_headers returned_data['headers'] = request_headers # 验证requestBody格式 list[dict] if 'requestBody' in test_case and not isinstance(test_case['requestBody'], list): raise TypeError("requestBody must be a list") if 'requestBody' in test_case and isinstance(test_case['requestBody'], list): for list_item in test_case['requestBody']: if not isinstance(list_item, dict): raise TypeError("requestBody must be a dict list") if 'requestBody' in test_case and len(test_case['requestBody']) > 0: if test_case['requestMethod'].lower() == 'get': request_url += '?' for key, value in test_case['requestBody'][0].items(): if value is not None: request_url += '%s=%s&' % (key, value) request_url = fake.resolve_faker_var(init_faker_var=request_url) request_url = func_var.resolve_func_var(init_func_var=request_url) request_url = common.replace_global_var_for_str(init_var_str=request_url, global_var_dic=self.global_vars) request_url = common.resolve_int_var(init_int_str=request_url) request_url = request_url[0:(len(request_url) - 1)] returned_data['testCaseDetail']['url'] = request_url else: # list 先转 str,方便全局变量替换 test_case['requestBody'] = str(test_case['requestBody']) # 替换faker变量 request_body_str = fake.resolve_faker_var(init_faker_var=test_case['requestBody']) # 替换自定义函数function变量 request_body_str = func_var.resolve_func_var(init_func_var=test_case['requestBody']) # 全局替换 request_body_str = common.replace_global_var_for_str(init_var_str=request_body_str, global_var_dic=self.global_vars) # 替换requestBody中的Number类型(去除引号) request_body_str = common.replace_global_var_for_str(init_var_str=request_body_str, global_var_dic=self.global_vars, global_var_regex=r'\'\$num{.*?}\'', match2key_sub_string_start_index=6, match2key_sub_string_end_index=-2 ) # 替换 需要去除引号的 int变量 request_body_str = common.resolve_int_var(init_int_str=request_body_str) if 'isJsonArray' not in test_case or not test_case['isJsonArray']: request_body_str = request_body_str[1:-1] # 转回 dict or list request_body = ast.literal_eval(request_body_str) returned_data['testCaseDetail']['requestBody'] = request_body # 处理 全局变量 if 'setGlobalVars' in test_case and test_case['setGlobalVars'] not in [[], {}, "", None]: set_global_vars = test_case['setGlobalVars'] # add by Vincent-Lee for data initial # 2020-1-7 16:40:56 # 处理数据初始化 dataInitializes if 'dataInitializes' in test_case and test_case['dataInitializes'] not in ["", None, {}, {'': ''}]: if isinstance(test_case['headers'], list): returned_data["dataInitResult"] = [] for dataInitialize in test_case['dataInitializes']: if not dataInitialize['dbConfigId'].strip() == '': returned_data["dataInitResult"].append( execute_data_init(self.test_env_id, dataInitialize, self.global_vars)) # 处理 cookies for 用例组执行 test_case['cookies'] = [] for key, value in session.cookies.items(): cookie_dic = dict() cookie_dic['name'] = key cookie_dic['value'] = value test_case['cookies'].append(cookie_dic) returned_data['testCaseDetail']['cookies'] = test_case['cookies'] # 获取debug时保存的临时 cookies for 调试用例 if is_debug and not test_case.get('isClearCookie'): request_cookies = get_cookies_by_suite(test_case.get("testSuiteId")) returned_data['testCaseDetail']['cookies'] = request_cookies if request_cookies: cookie_jar = RequestsCookieJar() for cookie in request_cookies: cookie_jar.set(cookie['name'], cookie['value']) session.cookies.update(cookie_jar) try: if 'delaySeconds' in test_case and test_case['delaySeconds'] > 0: time.sleep(test_case['delaySeconds']) returned_data['testCaseDetail']['delaySeconds'] = test_case['delaySeconds'] else: returned_data['testCaseDetail']['delaySeconds'] = 0 if 'parameterType' in test_case and test_case["parameterType"] == "form": response = session.request(url=request_url, method=request_method, data=request_body, headers=request_headers, verify=False) elif 'parameterType' in test_case and test_case["parameterType"] == "file": if 'filePath' in test_case and test_case['filePath']: returned_data['testCaseDetail']['filePath'] = test_case['filePath'] files = {'file': open(test_case['filePath'], 'rb')} response = session.request(url=request_url, method=request_method, files=files, headers=request_headers, data=request_body, verify=False) else: response = session.request(url=request_url, method=request_method, json=request_body, headers=request_headers, verify=False) returned_data['elapsedSeconds'] = round(response.elapsed.total_seconds(), 3) if is_debug: # 保存的临时 cookies for 调试用例 response_cookies = [] for key, value in session.cookies.items(): cookie_dic = dict() cookie_dic['name'] = key cookie_dic['value'] = value response_cookies.append(cookie_dic) if len(response_cookies) > 0: save_cookies_for_suite(test_case.get("testSuiteId"), response_cookies) except BaseException as e: returned_data["status"] = 'failed' returned_data["testConclusion"].append( {'resultType': test_conclusion.get(1), 'reason': '请求失败, 错误信息: <%s> ' % e}) return returned_data response_status_code = response.status_code returned_data["responseStatusCode"] = response_status_code returned_data["responseData"] = response.text # checkResponseCode 校验处理 if 'checkResponseCode' in test_case and test_case['checkResponseCode'] not in ["", None]: check_response_code = test_case['checkResponseCode'] returned_data['checkResponseCode'] = check_response_code # checkSpendSeconds 校验处理 if 'checkSpendSeconds' in test_case and test_case['checkSpendSeconds'] > 0: check_spend_seconds = test_case['checkSpendSeconds'] returned_data['checkSpendSeconds'] = check_spend_seconds try: response_json = json.loads(response.text) if isinstance(response.text, str) and response.text.strip() else {} except BaseException as e: # 如果出现异常,表名接口返回格式不是json if set_global_vars and isinstance(set_global_vars, list): for set_global_var in set_global_vars: if isinstance(set_global_var, dict) and isinstance(set_global_var.get('name'), str) and set_global_var.get('name'): name = set_global_var.get('name') query = set_global_var.get('query') if query and isinstance(query, list): query = common.replace_global_var_for_list(init_var_list=query, global_var_dic=self.global_vars) print(query) value = common.dict_get(response.text, query) self.global_vars[name] = str(value) if value else value if is_debug: new_temp_suite_params[name] = str(value) if value else value # 保存临时suite 变量 if is_debug and new_temp_suite_params: temp_suite_params.update(new_temp_suite_params) save_temp_params_for_suite(test_case.get("testSuiteId"), temp_suite_params) if check_response_code and not str(response_status_code) == str(check_response_code): returned_data["status"] = 'failed' returned_data["testConclusion"].append( {'resultType': test_conclusion.get(1), 'reason': '响应状态码错误, 期待值: <%s>, 实际值: <%s>。\t' % (check_response_code, response_status_code)}) return returned_data if check_spend_seconds and check_spend_seconds < returned_data['elapsedSeconds']: returned_data["status"] = 'failed' returned_data["testConclusion"].append( {'resultType': test_conclusion.get(1), 'reason': '请求超时, 期待耗时: %s s, 实际耗时: %s s。\t' % ( check_spend_seconds, returned_data['elapsedSeconds'])}) return returned_data # check response number need_check_res_num = isinstance(test_case.get('checkResponseNumber'), list) and len( list(filter(lambda x: str(x.get('expressions').get('expectResult')).strip() == '', test_case.get('checkResponseNumber')))) < 1 returned_data['status'] = 'failed' if need_check_res_num else 'ok' returned_data["testConclusion"].append( {'resultType': test_conclusion.get(1), 'reason': '接口返回格式不是json,无法进行数值校验, 错误信息: %s, 接口返回为: %s ' % (e, response.text)}) \ if returned_data.get('status') and returned_data.get('status') == 'failed' else None # checkResponseBody 校验处理 if 'checkResponseBody' in test_case and test_case['checkResponseBody'] not in [[], {}, "", None]: if not isinstance(test_case['checkResponseBody'], list): raise TypeError('checkResponseBody must be list!') need_check_response_body = False for index, check_item in enumerate(test_case['checkResponseBody']): if not isinstance(check_item, dict) or 'regex' not in check_item or 'query' not in check_item or \ not isinstance(check_item['regex'], str) or not isinstance(check_item['query'], list): raise TypeError('checkResponseBody is not valid!') # 对校验结果进行全局替换 if len(check_item['regex']) > 0: need_check_response_body = True test_case['checkResponseBody'][index]['regex'] = common.replace_global_var_for_str( init_var_str=check_item['regex'], global_var_dic=self.global_vars) if check_item.get( 'regex') and isinstance(check_item.get('regex'), str) else '' # 警告!python判断空字符串为False if check_item.get('query') and isinstance(check_item.get('query'), list): test_case['checkResponseBody'][index]['query'] = common.replace_global_var_for_list( init_var_list=check_item['query'], global_var_dic=self.global_vars) if need_check_response_body: check_response_body = test_case['checkResponseBody'] returned_data['checkResponseBody'] = check_response_body if check_response_body: for check_item in check_response_body: regex = check_item['regex'] query = check_item['query'] real_value = common.dict_get(response.text, query) if real_value is None: returned_data["status"] = 'failed' returned_data["testConclusion"].append( {'resultType': test_conclusion.get(1), 'reason': '未找到匹配的正则校验的值(查询语句为: %s), 服务器响应为: %s' % (query, response.text)}) return returned_data result = re.search(regex, str(real_value)) # python 将regex字符串取了r''(原生字符串) if not result: returned_data["status"] = 'failed' returned_data["testConclusion"].append( {'resultType': test_conclusion.get(1), 'reason': '判断响应值错误(查询语句为: %s),响应值应满足正则: <%s>, 实际值: <%s> (%s)。(正则匹配时会将数据转化成string)\t' % (query, regex, real_value, type(real_value))}) if returned_data['status'] == 'ok': returned_data["testConclusion"].append({'resultType': test_conclusion.get(0), 'reason': '测试通过'}) return returned_data if set_global_vars and isinstance(set_global_vars, list): for set_global_var in set_global_vars: if isinstance(set_global_var, dict) and isinstance(set_global_var.get('name'), str) and set_global_var.get('name'): name = set_global_var.get('name') query = set_global_var.get('query') value = common.dict_get(response_json, query) self.global_vars[name] = str(value) if value else value if is_debug: new_temp_suite_params[name] = str(value) if value else value # 保存临时suite 变量 if is_debug and new_temp_suite_params: temp_suite_params.update(new_temp_suite_params) save_temp_params_for_suite(test_case.get("testSuiteId"), temp_suite_params) # checkResponseBody 校验处理 if 'checkResponseBody' in test_case and test_case['checkResponseBody'] not in [[], {}, "", None]: if not isinstance(test_case['checkResponseBody'], list): raise TypeError('checkResponseBody must be list!') need_check_response_body = False for index, check_item in enumerate(test_case['checkResponseBody']): if not isinstance(check_item, dict) or 'regex' not in check_item or 'query' not in check_item or \ not isinstance(check_item['regex'], str) or not isinstance(check_item['query'], list): raise TypeError('checkResponseBody is not valid!') # 对校验结果进行全局替换 if len(check_item['regex']) > 0: need_check_response_body = True test_case['checkResponseBody'][index]['regex'] = common.replace_global_var_for_str( init_var_str=check_item['regex'], global_var_dic=self.global_vars) if check_item.get( 'regex') and isinstance(check_item.get('regex'), str) else '' # 警告!python判断空字符串为False if check_item.get('query') and isinstance(check_item.get('query'), list): test_case['checkResponseBody'][index]['query'] = common.replace_global_var_for_list( init_var_list=check_item['query'], global_var_dic=self.global_vars) if need_check_response_body: check_response_body = test_case['checkResponseBody'] returned_data['checkResponseBody'] = check_response_body # checkResponseNumber 校验处理 if 'checkResponseNumber' in test_case and not test_case['checkResponseNumber'] in [[], {}, "", None]: if not isinstance(test_case['checkResponseNumber'], list): raise TypeError('checkResponseNumber must be list!') for index, check_item in enumerate(test_case['checkResponseNumber']): if not isinstance(check_item, dict) or 'expressions' not in check_item or not isinstance( check_item['expressions'], dict): raise TypeError('checkResponseNumber is not valid!') test_case['checkResponseNumber'][index]['expressions']['firstArg'] = common.replace_global_var_for_str( init_var_str=check_item['expressions']['firstArg'], global_var_dic=self.global_vars) if check_item['expressions'].get('firstArg') and isinstance( check_item['expressions'].get('firstArg'), str) else '' test_case['checkResponseNumber'][index]['expressions']['secondArg'] = common.replace_global_var_for_str( init_var_str=check_item['expressions']['secondArg'], global_var_dic=self.global_vars) if check_item['expressions'].get('secondArg') and isinstance( check_item['expressions'].get('secondArg'), str) else '' test_case['checkResponseNumber'][index]['expressions'][ 'expectResult'] = common.replace_global_var_for_str( init_var_str=check_item['expressions']['expectResult'], global_var_dic=self.global_vars) if check_item['expressions'].get('expectResult') and isinstance( check_item['expressions'].get('expectResult'), str) else '' check_response_number = test_case['checkResponseNumber'] returned_data['checkResponseNumber'] = [] if check_response_code and not str(response_status_code) == str(check_response_code): returned_data["status"] = 'failed' returned_data["testConclusion"].append( {'resultType': test_conclusion.get(1), 'reason': '响应状态码错误, 期待值: <%s>, 实际值: <%s>。\t' % (check_response_code, response_status_code)}) if check_spend_seconds and check_spend_seconds < returned_data['elapsedSeconds']: returned_data["status"] = 'failed' returned_data["testConclusion"].append( {'resultType': test_conclusion.get(1), 'reason': '请求超时, 期待耗时: %s s, 实际耗时: %s s。\t' % ( check_spend_seconds, returned_data['elapsedSeconds'])}) return returned_data if check_response_body: try: for check_item in check_response_body: regex = check_item['regex'] if regex.strip() == '': continue query = check_item['query'] real_value = common.dict_get(response_json, query) if real_value is None: returned_data["status"] = 'failed' returned_data["testConclusion"].append( {'resultType': test_conclusion.get(1), 'reason': '未找到正则校验的Json值(查询语句为: %s), 服务器响应为: %s' % (query, response_json)}) return returned_data result = re.search(regex, str(real_value)) # python 将regex字符串取了r''(原生字符串) if not result: returned_data["status"] = 'failed' returned_data["testConclusion"].append( {'resultType': test_conclusion.get(1), 'reason': '判断响应值错误(查询语句为: %s),响应值应满足正则: <%s>, 实际值: <%s> (%s)。(正则匹配时会将数据转化成string)\t' % (query, regex, real_value, type(real_value))}) except BaseException as e: returned_data["status"] = 'failed' returned_data["testConclusion"].append({'resultType': test_conclusion.get(1), 'reason': '判断响应值时报错, 错误信息: <%s>。\t' % e}) if check_response_number: try: for check_item in check_response_number: expressions = check_item['expressions'] if '' in expressions.values() or None in expressions.values(): continue expressions_str, result = common.get_numbers_compared_result(expressions) returned_data['checkResponseNumber'].append({'expression': expressions_str}) if not result: returned_data["status"] = 'failed' returned_data["testConclusion"].append( {'resultType': test_conclusion.get(1), 'reason': '判断数值错误(判断表达式为: %s)。\t' % expressions_str}) except BaseException as e: returned_data["status"] = 'failed' returned_data["testConclusion"].append({'resultType': test_conclusion.get(1), 'reason': '判断数值时报错, 错误信息: <%s>。\t ' % e}) if not returned_data["testConclusion"]: returned_data["status"] = 'ok' returned_data["testConclusion"].append({'resultType': test_conclusion.get(0), 'reason': '测试通过'}) return returned_data
def execute_single_test(self, test_case): returned_data = dict() returned_data["_id"] = test_case["_id"] returned_data["testConclusion"] = [] if not isinstance(test_case, dict): returned_data["status"] = 'failed' returned_data["testConclusion"].append('测试用例结构不正确! ') return returned_data def validate_test_case(test_case): compulsory_key_list = ['requestProtocol', 'route', 'requestMethod'] return all([compulsory_key in test_case.keys() for compulsory_key in compulsory_key_list]) if not validate_test_case(test_case): returned_data["status"] = 'failed' returned_data["testConclusion"].append('测试用例缺失必要参数! ') return returned_data if test_case.get('isClearCookie'): self.session.cookies.clear() session = self.session url = None method = None json_data = None headers = dict() check_http_code = None check_response_time = None check_response_data = None check_response_number = None check_response_similarity = None set_global_vars = None # for example {'status': ['status']} domain = test_case["domain"] if 'domain' in test_case and isinstance(test_case["domain"], str) and \ not test_case["domain"].strip() == '' else self.domain try: if 'requestProtocol' in test_case and 'route' in test_case: test_case['route'] = \ common.resolve_global_var(pre_resolve_var=test_case['route'], global_var_dic=self.global_vars) \ if isinstance(test_case['route'], str) else test_case['route'] url = '%s://%s%s' % (test_case['requestProtocol'].lower(), domain, test_case['route']) if 'requestMethod' in test_case: method = test_case['requestMethod'] if 'presendParams' in test_case and isinstance(test_case['presendParams'], dict): # dict 先转 str,方便全局变量替换 test_case['presendParams'] = str(test_case['presendParams']) # 转换 fake 数据 test_case['presendParams'] = common.resolve_fake_var(pre_resolve_var=test_case['presendParams']) # 全局替换 test_case['presendParams'] = common.resolve_global_var(pre_resolve_var=test_case['presendParams'], global_var_dic=self.global_vars) # 转回 dict test_case['presendParams'] = ast.literal_eval(test_case['presendParams']) json_data = test_case['presendParams'] if 'headers' in test_case and not test_case['headers'] in ["", None, {}, {'': ''}]: if isinstance(test_case['headers'], list): for header in test_case['headers']: if not header['name'].strip() == '': headers[header['name']] = \ common.resolve_global_var(pre_resolve_var=header['value'], global_var_dic=self.global_vars) \ if isinstance(header['value'], str) else headers[header['name']] else: raise TypeError('headers must be list!') if 'setGlobalVars' in test_case and not test_case['setGlobalVars'] in [[], {}, "", None]: set_global_vars = test_case['setGlobalVars'] headers = None if headers == {} else headers test_case['cookies'] = [] for key, value in session.cookies.items(): cookie_dic = dict() cookie_dic['name'] = key cookie_dic['value'] = value test_case['cookies'].append(cookie_dic) except BaseException as e: returned_data["status"] = 'failed' returned_data["testConclusion"].append('测试前置准备失败, 错误信息: <%s> ' % e) return returned_data try: use_json_data = len(list(filter(lambda x: str(x).lower() == 'content-type' and 'json' in headers[x], headers.keys() if headers else {}))) > 0 test_start = time.time() if test_case['requestMethod'].lower() == 'get': response = session.request(url=url, method=method, params=json_data, headers=headers, verify=False) else: response = session.request(url=url, method=method, json=json_data, headers=headers, verify=False) if use_json_data \ else session.request(url=url, method=method, data=json_data, headers=headers, verify=False) test_end = time.time() test_spending_time = round(test_end - test_start, 3) test_case['spendingTimeInSec'] = test_spending_time # response.encoding = 'utf-8' # print(response.headers) TODO 请求头断言 except BaseException as e: returned_data["status"] = 'failed' returned_data["testConclusion"].append('请求失败, 错误信息: <%s> ' % e) return returned_data test_case['headers'] = headers # 重新赋值生成报告时用 response_status_code = response.status_code returned_data["responseHttpStatusCode"] = response_status_code try: returned_data["responseData"] = response.content.decode('unicode-escape') except BaseException: returned_data["responseData"] = response.text try: response_json = json.loads(response.text) if isinstance(response.text, str) \ and response.text.strip() else {} except BaseException as e: if set_global_vars and isinstance(set_global_vars, list): for set_global_var in set_global_vars: if isinstance(set_global_var, dict) and isinstance(set_global_var.get('name'), str): name = set_global_var.get('name') query = set_global_var.get('query') value = common.dict_get(response.text, query) self.global_vars[name] = str(value) if value else value if 'checkHttpCode' in test_case and not test_case['checkHttpCode'] in ["", None]: check_http_code = test_case['checkHttpCode'] if check_http_code and not str(response_status_code) == str(check_http_code): returned_data["status"] = 'failed' returned_data["testConclusion"].append('响应状态码错误, 期待值: <%s>, 实际值: <%s>。\t' % (check_http_code, response_status_code)) return returned_data if 'checkResponseTime' in test_case and test_case['checkResponseTime']: check_response_time = test_case['checkResponseTime'] if check_response_time and float(test_spending_time) > float(check_response_time): returned_data["status"] = 'failed' returned_data["testConclusion"].append('响应时间过长, 期待值: <%s s>, 实际值: <%s s>。\t' % (check_response_time, test_spending_time)) return returned_data is_check_res_data_valid = isinstance(test_case.get('checkResponseData'), list) and \ len(list(filter(lambda x: str(x.get('regex')).strip() == '', test_case.get('checkResponseData')))) < 1 is_check_res_similarity_valid = isinstance(test_case.get('checkResponseSimilarity'), list) and \ len(list(filter(lambda x: isinstance(x.get('targetSimilarity'), type(None)), test_case.get('checkResponseSimilarity')))) < 1 is_check_res_number_valid = isinstance(test_case.get('checkResponseNumber'), list) and \ len(list(filter(lambda x: str(x.get('expressions').get('expectResult')).strip() == '', test_case.get('checkResponseNumber')))) < 1 if is_check_res_data_valid: if 'checkResponseData' in test_case and not test_case['checkResponseData'] in [[], {}, "", None]: if not isinstance(test_case['checkResponseData'], list): raise TypeError('checkResponseData must be list!') for index, crd in enumerate(test_case['checkResponseData']): if not isinstance(crd, dict) or 'regex' not in crd or 'query' not in crd or \ not isinstance(crd['regex'], str) or not isinstance(crd['query'], list): raise TypeError('checkResponseData is not valid!') # TODO 可开启/关闭 全局替换 test_case['checkResponseData'][index]['regex'] = \ common.resolve_global_var(pre_resolve_var=crd['regex'], global_var_dic=self.global_vars) if \ crd.get('regex') and isinstance(crd.get('regex'), str) else '' # 警告!python判断空字符串为False check_response_data = test_case['checkResponseData'] if check_response_data: try: for crd in check_response_data: regex = crd['regex'] if regex.strip() == '': continue query = crd['query'] # query 支持全局变量替换 for index, single_query in enumerate(query): query[index] = common.resolve_global_var(pre_resolve_var=single_query, global_var_dic=self.global_vars) result = re.search(regex, str(response.text)) # python 将regex字符串取了r''(原生字符串) if not result: returned_data["status"] = 'failed' returned_data["testConclusion"].append('判断响应值错误(查询语句为: %s), 响应值应满足正则: <%s>,\ 实际值: <%s> (%s)。(正则匹配时会将数据转化成string)\t' % ( query, regex, response.text, type(response.text))) except BaseException as e: returned_data["status"] = 'failed' returned_data["testConclusion"].append('判断响应值时报错, 错误信息: <%s>。\t' % e) # TODO 目前默认当 is_check_res_similarity_valid 和 is_check_res_number_valid 为真时,返回格式必须可转 json ,可优化 is_test_failed = is_check_res_number_valid or is_check_res_similarity_valid returned_data['status'] = 'failed' if is_test_failed else 'ok' returned_data["testConclusion"].append('服务器返回格式不是json, 错误信息: %s, 服务器返回为: %s ' % (e, response.text)) if returned_data.get('status') and \ returned_data.get( 'status') == 'failed' else None if returned_data['status'] == 'ok': returned_data["testConclusion"].append('测试通过') return returned_data if set_global_vars and isinstance(set_global_vars, list): for set_global_var in set_global_vars: if isinstance(set_global_var, dict) and isinstance(set_global_var.get('name'), str): name = set_global_var.get('name') query = set_global_var.get('query') value = common.dict_get(response_json, query) self.global_vars[name] = str(value) if value else value if 'checkHttpCode' in test_case and not test_case['checkHttpCode'] in ["", None]: check_http_code = test_case['checkHttpCode'] if 'checkResponseTime' in test_case and test_case['checkResponseTime']: check_response_time = test_case['checkResponseTime'] if 'checkResponseData' in test_case and not test_case['checkResponseData'] in [[], {}, "", None]: if not isinstance(test_case['checkResponseData'], list): raise TypeError('checkResponseData must be list!') for index, crd in enumerate(test_case['checkResponseData']): if not isinstance(crd, dict) or 'regex' not in crd or 'query' not in crd or \ not isinstance(crd['regex'], str) or not isinstance(crd['query'], list): raise TypeError('checkResponseData is not valid!') # TODO 可开启/关闭 全局替换 test_case['checkResponseData'][index]['regex'] = \ common.resolve_global_var(pre_resolve_var=crd['regex'], global_var_dic=self.global_vars) if \ crd.get('regex') and isinstance(crd.get('regex'), str) else '' # 警告!python判断空字符串为False check_response_data = test_case['checkResponseData'] if 'checkResponseSimilarity' in test_case and not test_case['checkResponseSimilarity'] in [[], {}, "", None]: if not isinstance(test_case['checkResponseSimilarity'], list): raise TypeError('checkResponseSimilarity must be list!') for index, crs in enumerate(test_case['checkResponseSimilarity']): if not isinstance(crs, dict) or 'baseText' not in crs or 'targetSimilarity' not in crs \ or 'compairedText' not in crs or not isinstance(crs['baseText'], str) \ or not isinstance(crs['compairedText'], str): raise TypeError('checkResponseSimilarity is not valid!') test_case['checkResponseSimilarity'][index]['baseText'] = \ common.resolve_global_var(pre_resolve_var=crs['baseText'], global_var_dic=self.global_vars) if \ crs.get('baseText') and isinstance(crs.get('baseText'), str) else '' test_case['checkResponseSimilarity'][index]['compairedText'] = \ common.resolve_global_var(pre_resolve_var=crs['compairedText'], global_var_dic=self.global_vars) if \ crs.get('compairedText') and isinstance(crs.get('compairedText'), str) else '' check_response_similarity = test_case['checkResponseSimilarity'] if 'checkResponseNumber' in test_case and not test_case['checkResponseNumber'] in [[], {}, "", None]: if not isinstance(test_case['checkResponseNumber'], list): raise TypeError('checkResponseNumber must be list!') for index, crn in enumerate(test_case['checkResponseNumber']): if not isinstance(crn, dict) or 'expressions' not in crn or \ not isinstance(crn['expressions'], dict): raise TypeError('checkResponseNumber is not valid!') test_case['checkResponseNumber'][index]['expressions']['firstArg'] = \ common.resolve_global_var(pre_resolve_var=crn['expressions']['firstArg'], global_var_dic=self.global_vars) if \ crn['expressions'].get('firstArg') and isinstance(crn['expressions'].get('firstArg'), str) else '' test_case['checkResponseNumber'][index]['expressions']['secondArg'] = \ common.resolve_global_var(pre_resolve_var=crn['expressions']['secondArg'], global_var_dic=self.global_vars) if \ crn['expressions'].get('secondArg') and isinstance(crn['expressions'].get('secondArg'), str) else '' test_case['checkResponseNumber'][index]['expressions']['expectResult'] = \ common.resolve_global_var(pre_resolve_var=crn['expressions']['expectResult'], global_var_dic=self.global_vars) if \ crn['expressions'].get('expectResult') and isinstance(crn['expressions'].get('expectResult'), str) else '' check_response_number = test_case['checkResponseNumber'] if check_http_code and not str(response_status_code) == str(check_http_code): returned_data["status"] = 'failed' returned_data["testConclusion"].append('响应状态码错误, 期待值: <%s>, 实际值: <%s>。\t' % (check_http_code, response_status_code)) if check_response_time and float(test_spending_time) > float(check_response_time): returned_data["status"] = 'failed' returned_data["testConclusion"].append('响应时间过长, 期待值: <%s s>, 实际值: <%s s>。\t' % (check_response_time, test_spending_time)) if check_response_data: try: for crd in check_response_data: regex = crd['regex'] if regex.strip() == '': continue query = crd['query'] # query 支持全局变量替换 for index, single_query in enumerate(query): query[index] = common.resolve_global_var(pre_resolve_var=single_query, global_var_dic=self.global_vars) real_value = common.dict_get(response_json, query) if real_value is None: returned_data["status"] = 'failed' returned_data["testConclusion"].append('未找到正则校验的Json值(查询语句为: %s), 服务器响应为: %s' % (query, response_json)) return returned_data result = re.search(regex, str(real_value)) # python 将regex字符串取了r''(原生字符串) if not result: returned_data["status"] = 'failed' returned_data["testConclusion"].append('判断响应值错误(查询语句为: %s), 响应值应满足正则: <%s>,\ 实际值: <%s> (%s)。(正则匹配时会将数据转化成string)\t' % (query, regex, real_value, type(real_value))) except BaseException as e: returned_data["status"] = 'failed' returned_data["testConclusion"].append('判断响应值时报错, 错误信息: <%s>。\t' % e) if check_response_number: try: for crn in check_response_number: expressions = crn['expressions'] # print(expressions) if '' in expressions.values() or None in expressions.values(): continue expressions_str, result = common.get_numbers_compared_result(expressions) if not result: returned_data["status"] = 'failed' returned_data["testConclusion"].append('判断数值错误(判断表达式为: %s)。\t' % expressions_str) except BaseException as e: returned_data["status"] = 'failed' returned_data["testConclusion"].append('判断数值时报错, 错误信息: <%s>。\t ' % e) if hasattr(self, 'nlper') and self.nlper and check_response_similarity: try: for crs in check_response_similarity: base_text = crs['baseText'] compaired_text = crs['compairedText'] target_similarity = crs['targetSimilarity'] if base_text.strip() == '' or compaired_text.strip() == '' or \ not common.can_convert_to_float(target_similarity): continue actual_similarity = self.nlper.get_text_similarity(base_text, compaired_text) if float(actual_similarity) < float(target_similarity): returned_data["status"] = 'failed' returned_data["testConclusion"].append('相似度校验未达标!已对比字符串: 「%s」、「%s」, 实际相似度: 「%s」 ' '预期相似度: 「%s」。\t ' % (base_text, compaired_text, actual_similarity, target_similarity)) except BaseException as e: returned_data["status"] = 'failed' returned_data["testConclusion"].append('判断相似度时报错, 模型服务器可能已宕机/断网。具体错误信息: <%s>。\t' % e) if returned_data["testConclusion"] == []: returned_data["status"] = 'ok' returned_data["testConclusion"].append('测试通过') else: returned_data["status"] = 'failed' returned_data["testConclusion"].append('测试不通过!') return returned_data
def execute_single_case_test(self, test_case): returned_data = dict() returned_data["_id"] = ObjectId(test_case["_id"]) returned_data["testConclusion"] = [] # 存储 处理过后的testCaseDetail returned_data["testCaseDetail"] = {} if not isinstance(test_case, dict): returned_data["status"] = 'failed' returned_data["testConclusion"].append({ 'resultType': test_conclusion.get(2), 'reason': "测试用例结构不正确" }) return returned_data def validate_test_case(case): required_key_list = ['requestProtocol', 'route', 'requestMethod'] return all( [required_key in case for required_key in required_key_list]) if not validate_test_case(test_case): returned_data["status"] = 'failed' returned_data["testConclusion"].append({ 'resultType': test_conclusion.get(2), 'reason': "接口必要参数不完整" }) return returned_data if test_case.get('isClearCookie'): self.session.cookies.clear() session = self.session request_url = None request_method = None request_headers = dict() request_body = None check_response_code = None check_response_body = None check_response_number = None set_global_vars = None # for example {'user': ['data','user']} # 获取接口domain if 'domain' in test_case and isinstance( test_case["domain"], str) and not test_case["domain"].strip() == '': domain = test_case["domain"] else: domain = self.domain # 替换domain中的${service} (如果存在) if 'service' in test_case and isinstance(test_case["service"], str) \ and not test_case["service"].strip() == '': domain = common.replace_global_var_for_str( init_var_str=domain, global_var_dic={'service': test_case["service"]}) # 处理url protocol+domain+route route = common.replace_global_var_for_str(init_var_str=test_case['route'], global_var_dic=self.global_vars) \ if isinstance(test_case['route'], str) else test_case['route'] request_url = '%s://%s%s' % (test_case['requestProtocol'].lower(), domain, route) returned_data['testCaseDetail']['url'] = request_url # 获取method request_method = test_case['requestMethod'] returned_data['testCaseDetail']['requestMethod'] = request_method # 处理headers if 'headers' in test_case and test_case['headers'] not in [ "", None, {}, { '': '' } ]: if isinstance(test_case['headers'], list): for header in test_case['headers']: if not header['name'].strip() == '': request_headers[header['name']] = common.replace_global_var_for_str( init_var_str=header['value'], global_var_dic=self.global_vars) \ if isinstance(header['value'], str) else header['value'] else: raise TypeError('headers must be list!') request_headers = None if request_headers == {} else request_headers returned_data['headers'] = request_headers # 验证requestBody格式 list[dict] if 'requestBody' in test_case and not isinstance( test_case['requestBody'], list): raise TypeError("requestBody must be a list") if 'requestBody' in test_case and isinstance(test_case['requestBody'], list): for list_item in test_case['requestBody']: if not isinstance(list_item, dict): raise TypeError("requestBody must be a dict list") if 'requestBody' in test_case and len(test_case['requestBody']) > 0: if test_case['requestMethod'].lower() == 'get': request_url += '?' for key, value in test_case['requestBody'][0].items(): if value is not None: request_url += '%s=%s&' % (key, value) request_url = common.replace_global_var_for_str( init_var_str=request_url, global_var_dic=self.global_vars) request_url = request_url[0:(len(request_url) - 1)] returned_data['testCaseDetail']['url'] = request_url else: # list 先转 str,方便全局变量替换 test_case['requestBody'] = str(test_case['requestBody']) # 全局替换 request_body_str = common.replace_global_var_for_str( init_var_str=test_case['requestBody'], global_var_dic=self.global_vars) # 替换requestBody中的Number类型(去除引号) request_body_str = common.replace_global_var_for_str( init_var_str=request_body_str, global_var_dic=self.global_vars, global_var_regex=r'\'\$num{.*?}\'', match2key_sub_string_start_index=6, match2key_sub_string_end_index=-2) if 'isJsonArray' not in test_case or not test_case[ 'isJsonArray']: request_body_str = request_body_str[1:-1] # 转回 dict or list request_body = ast.literal_eval(request_body_str) returned_data['testCaseDetail']['requestBody'] = request_body # 处理 全局变量 if 'setGlobalVars' in test_case and test_case['setGlobalVars'] not in [ [], {}, "", None ]: set_global_vars = test_case['setGlobalVars'] # add by Vincent-Lee for data initial # 2020-1-7 16:40:56 # 处理数据初始化 dataInitializes if 'dataInitializes' in test_case and test_case[ 'dataInitializes'] not in ["", None, {}, { '': '' }]: if isinstance(test_case['headers'], list): returned_data["dataInitResult"] = [] for dataInitialize in test_case['dataInitializes']: if not dataInitialize['dbConfigId'].strip() == '': returned_data["dataInitResult"].append( execute_data_init(self.test_env_id, dataInitialize, self.global_vars)) # 处理 cookies test_case['cookies'] = [] for key, value in session.cookies.items(): cookie_dic = dict() cookie_dic['name'] = key cookie_dic['value'] = value test_case['cookies'].append(cookie_dic) returned_data['testCaseDetail']['cookies'] = test_case['cookies'] try: response = session.request(url=request_url, method=request_method, json=request_body, headers=request_headers, verify=False) except BaseException as e: returned_data["status"] = 'failed' returned_data["testConclusion"].append({ 'resultType': test_conclusion.get(1), 'reason': '请求失败, 错误信息: <%s> ' % e }) return returned_data response_status_code = response.status_code returned_data["responseStatusCode"] = response_status_code returned_data["responseData"] = response.text try: response_json = json.loads(response.text) if isinstance( response.text, str) and response.text.strip() else {} except BaseException as e: # 如果出现异常,表明服务器返回格式不是json if set_global_vars and isinstance(set_global_vars, list): for set_global_var in set_global_vars: if isinstance(set_global_var, dict) and isinstance( set_global_var.get('name'), str): name = set_global_var.get('name') query = set_global_var.get('query') if query and isinstance(query, list): query = common.replace_global_var_for_list( init_var_list=query, global_var_dic=self.global_vars) value = common.dict_get(response.text, query) self.global_vars[name] = str(value) if value else value if 'checkResponseCode' in test_case and test_case[ 'checkResponseCode'] not in ["", None]: check_response_code = test_case['checkResponseCode'] returned_data['checkResponseCode'] = check_response_code if check_response_code and not str(response_status_code) == str( check_response_code): returned_data["status"] = 'failed' returned_data["testConclusion"].append({ 'resultType': test_conclusion.get(1), 'reason': '响应状态码错误, 期待值: <%s>, 实际值: <%s>。\t' % (check_response_code, response_status_code) }) return returned_data is_check_res_body_valid = isinstance( test_case.get('checkResponseBody'), list) and len( list( filter(lambda x: str(x.get('regex')).strip() == '', test_case.get('checkResponseBody')))) < 1 is_check_res_num_valid = isinstance( test_case.get('checkResponseNumber'), list) and len( list( filter( lambda x: str( x.get('expressions').get('expectResult') ).strip() == '', test_case.get('checkResponseNumber')))) < 1 is_test_failed = is_check_res_body_valid or is_check_res_num_valid returned_data['status'] = 'failed' if is_test_failed else 'ok' returned_data["testConclusion"].append( {'resultType': test_conclusion.get(1), 'reason': '服务器返回格式不是json, 错误信息: %s, 服务器返回为: %s ' % (e, response.text)}) \ if returned_data.get('status') and returned_data.get('status') == 'failed' else None if returned_data['status'] == 'ok': returned_data["testConclusion"].append({ 'resultType': test_conclusion.get(0), 'reason': '测试通过' }) return returned_data if set_global_vars and isinstance(set_global_vars, list): for set_global_var in set_global_vars: if isinstance(set_global_var, dict) and isinstance( set_global_var.get('name'), str): name = set_global_var.get('name') query = set_global_var.get('query') value = common.dict_get(response_json, query) self.global_vars[name] = str(value) if value else value # 校验处理 # checkResponseCode if 'checkResponseCode' in test_case and test_case[ 'checkResponseCode'] not in ["", None]: check_response_code = test_case['checkResponseCode'] returned_data['checkResponseCode'] = check_response_code # checkResponseBody if 'checkResponseBody' in test_case and test_case[ 'checkResponseBody'] not in [[], {}, "", None]: if not isinstance(test_case['checkResponseBody'], list): raise TypeError('checkResponseBody must be list!') for index, check_item in enumerate(test_case['checkResponseBody']): if not isinstance(check_item, dict) or 'regex' not in check_item or 'query' not in check_item or \ not isinstance(check_item['regex'], str) or not isinstance(check_item['query'], list): raise TypeError('checkResponseBody is not valid!') # TODO 可开启/关闭 全局替换 # 对校验结果进行全局替换 test_case['checkResponseBody'][index][ 'regex'] = common.replace_global_var_for_str( init_var_str=check_item['regex'], global_var_dic=self.global_vars ) if check_item.get('regex') and isinstance( check_item.get('regex'), str) else '' # 警告!python判断空字符串为False if check_item.get('query') and isinstance( check_item.get('query'), list): test_case['checkResponseBody'][index][ 'query'] = common.replace_global_var_for_list( init_var_list=check_item['query'], global_var_dic=self.global_vars) check_response_body = test_case['checkResponseBody'] returned_data['checkResponseBody'] = check_response_body # checkResponseNumber if 'checkResponseNumber' in test_case and not test_case[ 'checkResponseNumber'] in [[], {}, "", None]: if not isinstance(test_case['checkResponseNumber'], list): raise TypeError('checkResponseNumber must be list!') for index, check_item in enumerate( test_case['checkResponseNumber']): if not isinstance( check_item, dict ) or 'expressions' not in check_item or not isinstance( check_item['expressions'], dict): raise TypeError('checkResponseNumber is not valid!') test_case['checkResponseNumber'][index]['expressions'][ 'firstArg'] = common.replace_global_var_for_str( init_var_str=check_item['expressions']['firstArg'], global_var_dic=self.global_vars ) if check_item['expressions'].get( 'firstArg') and isinstance( check_item['expressions'].get('firstArg'), str) else '' test_case['checkResponseNumber'][index]['expressions'][ 'secondArg'] = common.replace_global_var_for_str( init_var_str=check_item['expressions']['secondArg'], global_var_dic=self.global_vars ) if check_item['expressions'].get( 'secondArg') and isinstance( check_item['expressions'].get('secondArg'), str) else '' test_case['checkResponseNumber'][index]['expressions'][ 'expectResult'] = common.replace_global_var_for_str( init_var_str=check_item['expressions']['expectResult'], global_var_dic=self.global_vars ) if check_item['expressions'].get( 'expectResult') and isinstance( check_item['expressions'].get('expectResult'), str) else '' check_response_number = test_case['checkResponseNumber'] returned_data['checkResponseNumber'] = [] if check_response_code and not str(response_status_code) == str( check_response_code): returned_data["status"] = 'failed' returned_data["testConclusion"].append({ 'resultType': test_conclusion.get(1), 'reason': '响应状态码错误, 期待值: <%s>, 实际值: <%s>。\t' % (check_response_code, response_status_code) }) if check_response_body: try: for check_item in check_response_body: regex = check_item['regex'] if regex.strip() == '': continue query = check_item['query'] real_value = common.dict_get(response_json, query) if real_value is None: returned_data["status"] = 'failed' returned_data["testConclusion"].append({ 'resultType': test_conclusion.get(1), 'reason': '未找到正则校验的Json值(查询语句为: %s), 服务器响应为: %s' % (query, response_json) }) return returned_data result = re.search( regex, str(real_value)) # python 将regex字符串取了r''(原生字符串) if not result: returned_data["status"] = 'failed' returned_data["testConclusion"].append({ 'resultType': test_conclusion.get(1), 'reason': '判断响应值错误(查询语句为: %s),响应值应满足正则: <%s>, 实际值: <%s> (%s)。(正则匹配时会将数据转化成string)\t' % (query, regex, real_value, type(real_value)) }) except BaseException as e: returned_data["status"] = 'failed' returned_data["testConclusion"].append({ 'resultType': test_conclusion.get(1), 'reason': '判断响应值时报错, 错误信息: <%s>。\t' % e }) if check_response_number: try: for check_item in check_response_number: expressions = check_item['expressions'] if '' in expressions.values( ) or None in expressions.values(): continue expressions_str, result = common.get_numbers_compared_result( expressions) returned_data['checkResponseNumber'].append( {'expression': expressions_str}) if not result: returned_data["status"] = 'failed' returned_data["testConclusion"].append({ 'resultType': test_conclusion.get(1), 'reason': '判断数值错误(判断表达式为: %s)。\t' % expressions_str }) except BaseException as e: returned_data["status"] = 'failed' returned_data["testConclusion"].append({ 'resultType': test_conclusion.get(1), 'reason': '判断数值时报错, 错误信息: <%s>。\t ' % e }) if not returned_data["testConclusion"]: returned_data["status"] = 'ok' returned_data["testConclusion"].append({ 'resultType': test_conclusion.get(0), 'reason': '测试通过' }) return returned_data