API 接口自动化测试详细图文教程学习系列29--处理文件上传和优化状态码断言方式 测试学习记录仅供参考文件上传处理如果说需要测试文件上传接口可以按以下方式来处理本次测试项目服务接口并没有实际上的文件上传操作因此仅供参考学习了解在项目根目录 testcases 软件包 userManager 目录文件路径下新建名称为“filelmport.yaml” 的文件并输入以下内容自定义文件名称用于测试文件上传例如有如下格式要求建议根据实际要求填写baseInfo 数据信息段api_name: 文件上传接口名url: 文件上传地址method: 请求方式testCase 数据信息段文件上传接口测试用例case_name文件上传接口测试用例正常情况、异常状态、复杂情况、其他情况等等比如限制文件上传的格式文件大小等得分别进行测试data上传参数有些上传接口的入参需要传递额外特定的参数需要根据实际情况来区分判断若有的话就根据参数类型来书写files如若不需要上传参数的话则根据“files文件上传接口的关键词表示这个 yaml 文件就是一个文件上传接口 ”然后继续写上传参数一般上传参数的都是“file可根据实际场景更改”后面跟需要上传的具体文件的相对路径例如要上传“login.yaml”文件把数据放到 datas 目录文件下方便统一进行管理这样就填写完成了一个文件上传的基本格式仅供参考需根据实际需要场景- baseInfo: api_name: 文件上传接口 url: /dar/user/upload method: post testCase: - case_name: 文件正常上传 files: file: ./datas/login.yaml validation: - eq: {msg:登录成功} - code: 200修改项目根目录 unit_tools 软件包下“apiutils.py”文件内容添加文件上传处理代码# 导包 import json import jsonpath from unit_tools.handle_data.yaml_handler import read_yaml, write_yaml import re from unit_tools.debugtalk import DebugTalk # 引入 配置文件模块 from unit_tools.handle_data.configParse import ConfigParser # 引入 发起请求模块 from unit_tools.sendrequests import SendRequests # 引入 断言类 from unit_tools.assertion_utils import Assertions # 导入模块 import traceback # 创建一个类 RequestsBase class RequestsBase: # 在RequestsBase类的里面写一个初始化构造函数 def __init__(self): # 实例化一下实例化之后就可以通过这个对象去获取 host self.conf ConfigParser() # 实例化 self.send_request SendRequests() # 实例化断言类 self.asserts Assertions() # 创建一个方法 parse_and_replace_variables解析并且替换变量--传一个参数 yml_data--要解析的yaml文件的数组 def parse_and_replace_variables(self, yml_data): 解析并替换YAML文件数据中的变量引用如${get_extract_data(goodsId,1)} :param yml_data: 解析的YAML数据 :return: 最终要返回的是dict类型--才能给后续的一些方法调用时使用 # if isinstance(yml_data, str)--判断传进来的数据是什么类型--后续需要字符串才能做操作的所以这里先判断是不是字符串格式 # yml_data若是字符串则执行 if 语句左边的代码 直接返回yml_data # yml_data不是字符串--调用json.dumps(yml_data)模块转成字符串--ensure_asciiFalse 参数是可以处理中文 # if else 语句写在一行是 三元运算--通过这一系列之后最终返回一个 新的变量yaml_data_str --它是一个字符串 yml_data_str yml_data if isinstance(yml_data, str) else json.dumps(yml_data, ensure_asciiFalse) # 打印查看 yaml_data_str # print(f解析前{yml_data_str}) # 用for循环去判断 字符串yml_data_str里面这种标识 ${ 格式出现的次数--加一个_下划线表示不需要用到这个变量是一个占位符的意思 for _ in range(yml_data_str.count(${)): # if判断这个标识${ 它包含在字符串yml_data_str里面--并且另一半它 } 也包含在字符串yml_data_str里面 if ${ in yml_data_str and } in yml_data_str: # 通过获取到 ${ 标识的起始位置--通过字符串 yml_data_str 的索引 index--获取它的索引的起始位置 strat_index yml_data_str.index(${) # 获取结束位置 标识 }--再加一个参数 它的开头 strat_index end_index yml_data_str.index(}, strat_index) # 拿到开始、结束位置后--通过字符串切片--起始位置、结束位置1--为什么1--因为python中索引切片是左闭右开的一个规则 # 什么是左闭右开--开始位置是包含在切片里面的但是结束元素不包含在切片中所以得1 variable_data yml_data_str[strat_index:end_index1] # 使用正则表达式提取函数名和参数 # 导入re模块--调用re模块中的match方法--里面跟两个参数第一个参数是正则表达式第二个参数是要提取正则表达式的字符串 match re.match(r\$\{(\w)\((.*?)\)\}, variable_data) # 判断一下有没有匹配到--匹配的对象是不是成功了--成功 if match: # 通过match.groups()去拿到函数名还有参数--定义两个变量去接收,第一个函数名func_name、第二个函数值func_params func_name, func_params match.groups() # 先判断它存在--走if左边的代码--给它做一个切片若参数值不存在则返回一个空列表即可 # 参数值有一个或多个--所以需要做一个处理--参数值func_params通过逗号去做一个切片 # 最后再把值重新赋值给它自己 func_params func_params.split(,) if func_params else [] # 使用面向对象反射getattr调用函数 # 引如类后直接 实例化类--第二个参数传的是一个函数名 func_name--函数调用 (*func_params)--通过星号把参数值func_params去解包传递给参数func_name extract_data getattr(DebugTalk(), func_name)(*func_params) # print(f提取到的结果:{extract_data}) # 使用正则表达式替换原始字符串中的变量引用为调用后的结果 # 使用正则表达式替换函数re.sub--第一个参数就是需要替换的哪个参数值第二个参数是解析后得到的数据extract_data第三个参数是原始解析前的yml_data_str yml_data_str re.sub(re.escape(variable_data), str(extract_data), yml_data_str) # 还原数据将其转换为字典类型 # 添加异常处理--像这种转换的最好是加一个异常处理 try: # 直接调用 son.loads(yml_data_str)--把字符串转换成字典 data json.loads(yml_data_str) # json转码异常 except json.JSONDecodeError: # 返回原始数据yml_data_str--赋值给新变量 data data yml_data_str return data # 写个方法 execute_test_cases--传一个参数 接口的信息--即写yaml文件信息 def execute_test_cases(self, api_info): 规范yaml接口信息执行接口、提取结果以及断言操作 :param api_info: :return: # 先打印查看api_info信息 print(api_info) # 添加异常 try: # 处理baseInfo里面的数据 # 获取到接口的服务器地址--通过读取配置文件去获取--通过这个对象去调用 conf_host self.conf.get_host(host) # 获取url--完整的url是通过 服务器地址 加上 接口信息api_info url conf_host api_info[baseInfo][url] # 接口名称 api_name api_info[baseInfo][api_name] # 请求方式 method api_info[baseInfo][method] # 请求头--通过get方法获取看里面有没有请求头--如果有的话就返回给变量headers若没有则传个默认空值None就行 # 判断请求头是否可选使用get的话当headers有的话就返回没有时就返回None不至于报错 headers api_info[baseInfo].get(headers, None) # 再进行一步处理--判断 headers 不为空 if headers is not None: # if isinstance(headers, str) 判断headers是什么类型--如果是一个字符串str类型的话 就需要给它做一个解析 # self.parse_and_replace_variables(headers) 调用parse_and_replace_variables方法把headers给传进来 # else headers 若不是字符串直接给他返回headers # headers 最后再把结果传回给它自己就行了 # eval() 调用一个函数 把解析后的数据 self.parse_and_replace_variables(headers) 转换为 字典类型 headers eval(self.parse_and_replace_variables(headers)) if isinstance(headers, str) else headers # print(headers) # cookies 与 请求头一样 cookies api_info[baseInfo].get(cookies, None) if cookies is not None: cookies eval(self.parse_and_replace_variables(cookies)) if isinstance(cookies, str) else cookies # print(cookies) # 处理testCase里面的数据 # 通过for循环--循环testcase--通过读取api_info--拿到最外层的数据testCase for testcase in api_info[testCase]: print(f处理前{testcase}) # 拿到之后进行更近一步的处理--通过testcase.pop()去处理--先获取它第一组数据 case_name case_name testcase.pop(case_name) # 通过变量引用处理断言结果 # 通过self.parse_and_replace_variables去断言解析的函数--通过for循环中testcase.get获取断言的关键词validation # 然后拿到validation后面的这组数据--再把断言的结果值给返回出去并赋值给变量val_result val_result self.parse_and_replace_variables(testcase.get(validation)) # print(val_result) # 拿到断言结果继续往下写--把testcase[validation]这个值更新成处理后的数据val_result testcase[validation] val_result # 同样是调用pop--然后去获取这个数据variables--最后把结果返回出去给variables validation testcase.pop(validation) # print(validation, type(validation)) # print(testcase, type(testcase)) # 处理接口返回值提取部分 # 通过testcase.pop去删除删除之前再把结果返回即返回再删除--获取extract关键词结果 # --可以在跟一个参数设置默认值当login.yaml文件中有extract这个值的时候就返回没有返回一个None它就不会报错了 # extract testcase.pop(extract, None) # print(extract) # 处理为 列表的情况 extract_list--要把每一种情况都考虑进去 # extract_list testcase.pop(extract_list, None) # print(extract_list) # 把extract、extract_list 写在一行--看个人习惯分开写或者一起都行 extract, extract_list testcase.pop(extract, None), testcase.pop(extract_list, None) print(f处理后{testcase}) # 处理参数类型和请求参数 # 使用for循环--参数类型param_type、参数值param_value--它是一个字典直接通过testcase.items() 字典函数 for param_type, param_value in testcase.items(): # 拿到之后开始进一步操作 # print(f类型{param_type}, 参数值{param_value}) # 先判断类型 param_type 在不在这三种其中之一--也就是说参数类型只能写这三种里面的一个 if param_type in [params, data, json]: # 若是在的话则可以解析了--直接去调用解析的方法--把参数值param_value传递给它--最后再把结果返回出去赋值给变量request_params request_params self.parse_and_replace_variables(param_value) # print(request_params) # 把testcase字典key值 参数类型更新为 通过解析之后的数据 request_params testcase[param_type] request_params print(处理之后, testcase) # 文件上传处理 files testcase.pop(files, None) if files: for fk, fv in files.items(): files {fk: open(fv, moderb)} # 通过刚刚创建的实例化对象self.send_request去调用执行接口请求的方法execute_api_request()--里面的参数需要一一对应 # **kwargs 未知数量传参————直接把 **testcase 传给它 response self.send_request.execute_api_request(api_nameapi_name, urlurl, methodmethod, headerheaders, case_namecase_name, cookiecookies, filefiles, **testcase) # 获取状态码和接口返回结果的text文本格式 status_code, response_text response.status_code, response.text print(response_text) # 处理接口返回值提取 # 判断这个值extract不等于None的话 if extract is not None: # 就调用封装的方法extract_data--传递--第一个参数extract————第二个参数response self.extract_data(extract, response_text) # 判断这个值extract_list不等于None的话 if extract_list is not None: # 调用封装的方法extract_data_list--传递--第一个参数extract_list————第二个参数response self.extract_data_list(extract_list, response_text) # 处理接口断言 self.asserts.assert_result(validation, response.json(), status_code) except Exception as e: # 因暂时未写日志模块所以这里先打印出来 # {str(traceback.format_exc())}--当出现异常时会打印出比较详细的信息 print(f出现未知异常--{str(traceback.format_exc())}) # 这里出现异常时需手动抛出异常--在生成报告时这里若没有抛出这个异常的话在测试出现失败时还是会统计为成功的 raise e # 创建一个方法 extract_data 提取接口的返回值--接收两个参数testcase_extract就是yaml文件中的token: $.token————response_text 接口返回信息文本格式 classmethod def extract_data(cls, testcase_extract, response_text): 提取单个参数提取接口的返回参数支持正则表达式提取和json提取器 :param testcase_extract: (dict)yaml文件中的extract值例如{‘token’:$.token} :param response_text: str接口的实际返回值 :return: # 先打印一下表达式 {‘token’:$.token} # print(testcase_extract) extract_data None try: # 使用for循环————因为这个值token: $.token是一个字典类型要分别去拿到要提取变量的名称token还有后面拿到表达式$.token for key, value in testcase_extract.items(): # any() 函数是 当里面的元素都为真True的情况下就返回True————则if通过才会执行下面的语句————这里其实是一个生成器表达式 # 使用for循环里面的列表————正则表达式贪婪匹配、非贪婪匹配 # (.*?)只是匹配0次或多次 (.?)只是匹配1次或多次 # r(\d)、r(\d*)加 r 是防止被转义\d 是获取数字 加号是获取至少1次或多次* 星号是至少0次 if any(pat in value for pat in [(.*?), (.?), r(\d), r(\d*)]): # 使用正则表达式的模块调用search函数去全局的搜索--第一个参数是它的正则表达式value第二个是从接口的返回信息中去提取response_text ext_list re.search(value, response_text) # 把数据存储下来存到字典中--对值value进行一个判断--判断提取到的数据是字符串还是整数类型 # 先去判断 if r(\d) in value 有没有这个值有的话把它转成整数类型的 int(ext_list.group(1)) # 若不是 (\d) 则直接执行 else 后面的语句 ext_list.group(1) extract_data {key: int(ext_list.group(1)) if r(\d) in value else ext_list.group(1)} # print(f提取到的结果{extract_data}) # 判断有没有 $ 符号 elif $ in value: # 引入模块 import jsonpath --调用jsonpath()去提取--因为json提取需要json格式而response_text是字符串类型的 # 使用json.loads(response_text)转换成字典类型它才能提取--第二个值value--它最外层是列表所以需要索引[0]取值 extract_json jsonpath.jsonpath(json.loads(response_text), value)[0] # 拿到接口返回值token print(extract_json) # 先判断提取的结果是否存在--若存在则定义一个字典存储起来若不存在则直接提示打印一句话 extract_data {key: extract_json} if extract_json else {key: 未提取到数据请检查接口返回信息或表达式} # 提取到的结果 print(extract_data) # 判断extract_data是否存在 if extract_data: # 引入写入方法 write_yaml()--若存在则调用方法--把结果字典类型的extract_data给存进去 write_yaml(extract_data) except re.error: print(正则表达式解析错误请检查yaml文件extract表达式是否正确) except json.JSONDecodeError: print(JSON解析错误请检查yaml文件extract表达式是否正确) classmethod def extract_data_list(cls, testcase_extract_list, response_text): 提取多个参数提取接口的返回参数支持正则表达式提取和json提取器 :param testcase_extract_list: (dict)yaml文件中的extract_list值例如{‘token’:$.token} :param response_text: str接口的实际返回值 :return: extract_data None try: # 跟上面的方法一样先去循环拿到key值、value值 for key, value in testcase_extract_list.items(): if any(pat in value for pat in [(.*?), (.?), r(\d), r(\d*)]): # 使用正则表达式的模块调用findall函数--传参还是一样的-- re.S --re模块的一个选项表示在模式中匹配任何字符包括换行符 ext_list re.findall(value, response_text, re.S) print(ext_list) # 判断提取的结果对不对 if ext_list: # 存储起来 extract_data {key: ext_list} print(extract_data) # json提取器 elif $ in value: # 这里是提取多个是一个列表所以不需要通过索引[0]去取值 extract_json jsonpath.jsonpath(json.loads(response_text), value) print(extract_json) # 判断提取的这个值是否存在 if extract_json: extract_data {key: extract_json} else: extract_data {key: 未提取到数据请检查接口返回信息或表达式} # 判断extract_data是否存在 if extract_data: # 写入方法 write_yaml(extract_data) except re.error: print(正则表达式解析错误请检查yaml文件extract表达式是否正确) except json.JSONDecodeError: print(JSON解析错误请检查yaml文件extract表达式是否正确) # 测试调试查看 if __name__ __main__: # 先引进读取方法 read_yaml--传如一个它的相对路径--赋值给新变量data--[0]通过索引去列表值第一个 api_info read_yaml(.././datas/login.yaml)[0] # 实例化类 RequestsBase()--并赋值给一个变量对象 req req RequestsBase() # 通过类对象去调用parse_and_replace_variables(data) 这个解析的方法--把读取到的 data 这个yaml数据传给它 # res req.parse_and_replace_variables(data) # print(f解析后{res}) # 通过这个对象req去调用刚刚封装的方法execute_test_cases--把读取到yaml文件的数据api_info传给它 req.execute_test_cases(api_info)文件上传就这么简单现在先不写它的执行文件因为没有这个文件上传接口若以后有遇到的话可以通过这种方式去写需要注意的是“权限 rb”必须要以“二进制”模式打开因为在计算机中所有的数据包括“文本、图像、音频视频”等最终都是以“二进制”来存储处理的通过testcase 调用pop 函数如果这个 yaml 文件里面有此“files”关键词的话就删除并返回要是没有的话就返回一个默认 None 值if 判断“files”关键词如果不等于None 则进行下一步处理写个 for 循环 入参““file: ./datas/login.yaml””的参数名file和参数值./datas/login.yaml通过files.items()方法以字典格式分别拿到参数名、参数值需要上传的目标文件拿到之后再进一步操作假如说拿到之后给它定义了一个字典“{}”字典的 key 值就等于参数名 fkvalue 值value 是要上传的目标文件得先使用 open() 方法打开之后再上传给它发送到 request 模块去发起一个上传文件的接口请求,以二进制的模式打开 fv 这个文件最后把结果给返回出去文件上传处理会判断如果 yaml 文件里面有“files”关键词的话会进行处理先以二进制的模式打开要上传的文件然后把处理后的一个字典键值对给传递出去最后发起接口请求的时候以之前所约定的格式来处理# 文件上传处理 files testcase.pop(files, None) if files: for fk, fv in files.items(): files {fk: open(fv, moderb)}优化状态码断言假如把断言状态码写成了字符串格式则需要进一步处理状态码断言结果- baseInfo: api_name: 获取物料信息 url: /api/order/customer/orderPlan/getMaterial method: get headers: ${get_headers(data)} cookies: ${get_extract_data(Cookie)} testCase: - case_name: 获取物料信息 validation: - code: 200 - eq: {message:操作成功} extract_list: materIds: $.material[*]修改项目根目录 unit_tools 软件包下“assertion_utils.py”文件内容增加一个 if 判断判断断言状态码标识先判断它如果不是一个整数类型调用“isinstance”判断数据类型函数来判断“expected_result”期望结果不是整数类型的话就直接使用 int方法把 expected_result 预期结果强制转换成整数类型然后把转化之后的数据再传给它自己# -*- coding:utf-8 -*- # 引入内置模块--类型检测工具--指定类型 from typing import Callable,Any # 引入自定义异常 # from exception_utils.exception import AssertTypeError from unit_tools.exception_utils.exception import AssertTypeError import jsonpath import operator # 创建一个断言类 Assertions--里面有多种断言模式 class Assertions: 接口断言模式封装 1、状态码断言 2、包含模式断言 3、相等断言 4、不相等断言 5、数据库断言 # 封装成一个类方法 classmethod--说明这个方法不需要访问实例属性 classmethod # 定义一个方法status_code_assert--跟上两个参数 def status_code_assert(cls, expected_result, status_code): 接口的响应状态码断言 :param expected_result: yaml文件code模式中的预期状态码 :param status_code: 接口实际返回的状态码 :return: # 断言状态码标识0 表示成功其他表示失败 failure_count 0 # 先判断它如果不是一个整数类型--使用isinstance判断数据类型函数来判断expected_result不是整数类型 if not isinstance(expected_result, int): # 直接调用int方法给expected_result预期结果转换成整数类型然后把转化之后的数据再传给它自己 expected_result int(expected_result) # 直接判断 预期结果 等于 接口的实际返回状态码 if expected_result status_code: print(f状态码断言成功接口实际返回状态码 {status_code} {expected_result}) else: print(f状态码断言失败接口实际返回状态码 {status_code} {expected_result}) # 标识加1--加1之后就不等于0了表示失败 failure_count 1 # 最后把失败统计的标识返回出去 return failure_count classmethod # 包含模式断言 def contain_assert(cls, expected_result, response): 字符串包含模式断言预期结果字符串是否包含在接口的实际响应返回信息中 :param expected_result: yaml文件中的预期结果 :param response: 接口的实际返回值 :return: failure_count 0 # 调用字典中的items()分别拿到key值、value值 for assert_key, assert_value in expected_result.items(): # print(fkey值{assert_key} -- value值{assert_value}) # 通过调用jsonpath.jsonpath()方法去接口的实际响应结果response中 根据表达式 $.. 去提取 response_list jsonpath.jsonpath(response, f$..{assert_key}) # print(response_list) # 判断提取到的结果存不存在--并且是不是字符串类型 if response_list and isinstance(response_list[0], str): # 如果是字符串类型的话则重新组成一个字符串--把list数据转成字符串 response_str .join(response_list) # print(response_str) success_message f包含模式断言成功预期结果【{assert_value}】存在实际结果【{response_str}】中 failure_message f包含模式断言失败预期结果【{assert_value}】未存在没有在实际结果【{response_str}】中找到 # 判断assert_value是不是包含在response_str里面 if assert_value in response_str: print(success_message) else: failure_count 1 print(failure_message) return failure_count classmethod def equal_assert(cls, expected_result, response): 相等断言根据yaml里面的validation关键词下面的eq模式数据去跟接口实际响应信息对比 :param expected_result: dictyaml里面的eq值 :param response: dict接口实际响应结果 :return: failure_count 0 if isinstance(response, dict) and isinstance(expected_result, dict): # print(fyaml的预期结果{expected_result}) # print(f接口的实际结果{response}) # 找出实际结果与预期结果共同的key值 common_key list(expected_result.keys() response.keys()) if common_key: common_key common_key[0] # print(common_key) # 根据相同的key值去实际结果中获取并重新生成一个实际结果的字典 new_actual_result {common_key: response[common_key]} # print(new_actual_result) # 调用operator.eq()方法 eq_assert operator.eq(new_actual_result, expected_result) if eq_assert: print(f相等断言成功接口实际结果 {new_actual_result} 预期结果{expected_result}) else: failure_count 1 print(f相等断言失败接口实际结果 {new_actual_result} ! 预期结果{expected_result}) else: failure_count 1 print(相等断言失败请检查yaml文件eq模式的预期结果或接口返回值是否正确) return failure_count classmethod def not_equal_assert(cls, expected_result, response): 不相等断言根据yaml里面的validation关键词下面的ne模式数据去跟接口实际响应信息对比 :param expected_result: dictyaml里面的ne值 :param response: dict接口实际响应结果 :return: failure_count 0 if isinstance(response, dict) and isinstance(expected_result, dict): # print(fyaml的预期结果{expected_result}) # print(f接口的实际结果{response}) # 找出实际结果与预期结果共同的key值 common_key list(expected_result.keys() response.keys()) if common_key: common_key common_key[0] # print(common_key) # 根据相同的key值去实际结果中获取并重新生成一个实际结果的字典 new_actual_result {common_key: response[common_key]} # print(new_actual_result) # 调用operator.ne()方法 eq_assert operator.ne(new_actual_result, expected_result) if eq_assert: print(f不相等断言成功接口实际结果 {new_actual_result} ! 预期结果{expected_result}) else: failure_count 1 print(f不相等断言失败接口实际结果 {new_actual_result} 预期结果{expected_result}) else: failure_count 1 print(不相等断言失败请检查yaml文件ne模式的预期结果或接口返回值是否正确) return failure_count classmethod # 定义一个方法assert_result 用于管理多种断言模式 def assert_result(cls, expected_result, response, status_code): 断言主函数通过all_flag标记如all_flag 0 表示测试成功否则为失败 :param expected_result: listyaml文件validation关键词下面的预期结果 :param response: (dict)接口的实际响应信息 :param status_code: 接口的实际响应状态码 :return: all_flag 0 # 通过字典映射的关系去管理方法 assert_methods { code: cls.status_code_assert, contain: cls.contain_assert, eq: cls.equal_assert, ne: cls.not_equal_assert } try: # 先打印查看一下预期结果是什么类型 # print(f打印结果{expected_result}, 打印类型, type(expected_result)) print(f打印结果{expected_result}, 打印类型, type(expected_result)) # 通过for循环 拿到断言模式 for yq in expected_result: # print(yq) # 先拿到 断言模式assert_mode预期结果值assert_value--通过字典items()函数获取到每一个值 for assert_mode, assert_value in yq.items(): # print(f断言模式{assert_mode}--预期值{assert_value}) # 通过assert_methods.get(assert_mode)它的字典去读取对应的断言方法 # 表示assert_method是一个接收两个参数类型为Any表示可以是任意类型并返回整数的可调用对象 assert_method:Callable[[Any, Any], int] assert_methods.get(assert_mode) # 判断获取到的值存在 if assert_method: # 调用对应的断言方法传递适当的参数 if assert_mode code: # 返回一下标识 flag flag assert_method(assert_value, status_code) else: flag assert_method(assert_value, response) all_flag flag else: print(f不支持{assert_mode}该断言模式) # 手动抛出异常 raise AssertTypeError(f不支持{assert_mode}该断言模式) except Exception as exceptions: # print(exceptions) # 抛出异常 raise exceptions # 通过assert关键词去断言 标识all_flag 等于0即测试成功不等于0测试失败 assert all_flag 0, 测试失败 print(测试成功)未完待续。。。