Repository: Louis-me/auto_http_api Branch: master Commit: 5a7ff01845e4 Files: 31 Total size: 25.1 KB Directory structure: gitextract_qljz_wtl/ ├── .gitignore ├── Base/ │ ├── BaseElementEnmu.py │ ├── BaseEmail.py │ ├── BaseExcel.py │ ├── BaseFile.py │ ├── BaseGetExcel.py │ ├── BaseIni.py │ ├── BaseInit.py │ ├── BaseParams.py │ ├── BaseReq.py │ ├── BaseReq1.py │ ├── BaseRunner.py │ ├── BaseRunner1.py │ ├── BaseStatistics.py │ └── __init__.py ├── Log/ │ ├── info.pickle │ ├── param.txt │ └── param_result.txt ├── README.md ├── Report/ │ ├── Report.xlsx │ └── api.xlsx ├── Runner/ │ ├── __init__.py │ ├── runner.py │ ├── runner1.py │ └── start_test.bat ├── Setting/ │ └── Config.ini ├── TestCases/ │ ├── Api.py │ ├── Api1.py │ └── __init__.py ├── channel_log.md └── requirements.txt ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .idea ================================================ FILE: Base/BaseElementEnmu.py ================================================ import os PATH = lambda p: os.path.abspath( os.path.join(os.path.dirname(__file__), p) ) class Element(object): INFO_FILE = PATH("../Log/info.pickle") # 记录结果 REPORT_FILE = PATH("../Report/Report.xlsx") # 测试报告 API_FILE = PATH("../Report/api.xlsx") # 用例文件 PICT_PARAM = PATH("../Log/param.txt") # 写入pict需要的参数 PICT_PARAM_RESULT = PATH("../Log/param_result.txt") # pict生成后的数据 OPEN_PICT = PATH("../Setting/Config.ini") # 打开pict配置器 ERROR_EMPTY = "error_empty" ERROR_VALUE = "error_value" ================================================ FILE: Base/BaseEmail.py ================================================ # -*- coding: utf-8 -*- from email.header import Header from email.mime.text import MIMEText from email.utils import parseaddr, formataddr from email.mime.multipart import MIMEMultipart from email.mime.application import MIMEApplication import smtplib import os PATH = lambda p: os.path.abspath( os.path.join(os.path.dirname(__file__), p) ) def _format_addr(s): name, addr = parseaddr(s) return formataddr((Header(name, 'utf-8').encode(), addr)) def send_mail(**kwargs): ''' :param f: 附件路径 :param to_addr:发给的人 [] :return: ''' from_addr = kwargs["mail_user"] password = kwargs["mail_pass"] # to_addr = "ashikun@126.com" smtp_server = kwargs["mail_host"] msg = MIMEMultipart() # msg = MIMEText('hello, send by Python...', 'plain', 'utf-8') msg['From'] = _format_addr('来自<%s>接口测试' % from_addr) msg['To'] = _format_addr(' <%s>' % kwargs["to_addr"]) msg['Subject'] = Header(kwargs["header_msg"], 'utf-8').encode() msg.attach(MIMEText(kwargs["attach"], 'plain', 'utf-8')) if kwargs.get("report", "0") != "0": part = MIMEApplication(open(kwargs["report"], 'rb').read()) part.add_header('Content-Disposition', 'attachment', filename=('gb2312', '', kwargs["report_name"])) msg.attach(part) server = smtplib.SMTP_SSL(smtp_server, kwargs["port"]) server.set_debuglevel(1) server.login(from_addr, password) server.sendmail(from_addr, kwargs["to_addr"], msg.as_string()) server.quit() if __name__ == '__main__': to_addr = ["284772894@qq.com"] mail_host = "smtp.qq.com" mail_user = "284772894@qq.com" mail_pass = "oftllbhnknegbjhb" port = "465" header_msg = "接口测试" attach = "接口测试" report = PATH("../Log/report.xlsx") send_mail(to_addr = to_addr, mail_host = mail_host, mail_user=mail_user, port=port, mail_pass=mail_pass, header_msg=header_msg, report=report, attach=attach, report_name="接口测试报告") ================================================ FILE: Base/BaseExcel.py ================================================ __author__ = 'shikun' import xlsxwriter import os PATH = lambda p: os.path.abspath( os.path.join(os.path.dirname(__file__), p) ) class OperateReport: def __init__(self, wd): self.wd = wd def detail(self, worksheet, info): # 设置列行的宽高 worksheet.set_column("A:A", 30) worksheet.set_column("B:B", 20) worksheet.set_column("C:C", 20) worksheet.set_column("D:D", 20) worksheet.set_column("E:E", 20) worksheet.set_column("F:F", 20) worksheet.set_column("G:G", 20) worksheet.set_column("H:H", 20) worksheet.set_row(1, 30) worksheet.set_row(2, 30) worksheet.set_row(3, 30) worksheet.set_row(4, 30) worksheet.set_row(5, 30) worksheet.set_row(6, 30) worksheet.set_row(7, 30) worksheet.set_row(8, 30) worksheet.merge_range('A1:H1', '测试详情', get_format(self.wd, {'bold': True, 'font_size': 18, 'align': 'center', 'valign': 'vcenter', 'bg_color': 'blue', 'font_color': '#ffffff'})) _write_center(worksheet, "A2", '请求', self.wd) _write_center(worksheet, "B2", '方法', self.wd) _write_center(worksheet, "C2", '请求参数', self.wd) _write_center(worksheet, "D2", '请求说明', self.wd) _write_center(worksheet, "E2", '期望值', self.wd) _write_center(worksheet, "F2", '响应码 ', self.wd) _write_center(worksheet, "G2", '实际结果 ', self.wd) _write_center(worksheet, "H2", '是否通过 ', self.wd) temp = 3 for item in info: # print(item) _write_center(worksheet, "A" + str(temp), item["url"], self.wd) _write_center(worksheet, "B" + str(temp), item["method"], self.wd) _write_center(worksheet, "C" + str(temp), item["params"], self.wd) _write_center(worksheet, "D" + str(temp), item["msg"], self.wd) _write_center(worksheet, "E" + str(temp), item["hope"], self.wd) _write_center(worksheet, "F" + str(temp), item["code"], self.wd) _write_center(worksheet, "G" + str(temp), item["res"], self.wd) _write_center(worksheet, "H" + str(temp), item["result"], self.wd) temp += 1 def close(self): self.wd.close() def get_format(wd, option={}): return wd.add_format(option) # def link_format(wd): # red_format = wd.add_format({ # 'font_color': 'red', # 'bold': 1, # 'underline': 1, # 'font_size': 12, # }) def get_format_center(wd, num=1): return wd.add_format({'align': 'center', 'valign': 'vcenter', 'border': num}) def set_border_(wd, num=1): return wd.add_format({}).set_border(num) def _write_center(worksheet, cl, data, wd): return worksheet.write(cl, data, get_format_center(wd)) def set_row(worksheet, num, height): worksheet.set_row(num, height) # 生成饼形图 def pie(workbook, worksheet): chart1 = workbook.add_chart({'type': 'pie'}) chart1.add_series({ 'name': '自动化测试统计', 'categories': '=测试总况!$C$4:$C$5', 'values': '=测试总况!$D$4:$D$5', }) chart1.set_title({'name': '测试统计'}) chart1.set_style(10) worksheet.insert_chart('A9', chart1, {'x_offset': 25, 'y_offset': 10}) if __name__ == '__main__': sum = {'testSumDate': '25秒', 'sum': 10, 'pass': 5, 'testDate': '2017-06-05 15:26:49', 'fail': 5, 'appVersion': '17051515', 'appSize': '14M', 'appName': "'简书'"} info = [{"id": 1, "title": "第一次打开", "caseName": "testf01", "result": "通过", "phoneName": "三星"}, {"id": 1, "title": "第一次打开", "caseName": "testf01", "result": "通过", "img": "d:\\1.PNG", "phoneName": "华为"}] workbook = xlsxwriter.Workbook('Report.xlsx') worksheet = workbook.add_worksheet("测试总况") worksheet2 = workbook.add_worksheet("测试详情") bc = OperateReport(wd=workbook) bc.init(worksheet, sum) bc.detail(worksheet2, info) bc.close() # ================================================ FILE: Base/BaseFile.py ================================================ import os import time PATH = lambda p: os.path.abspath( os.path.join(os.path.dirname(__file__), p) ) ''' 操作文件 ''' class BaseFile(object): def __init__(self): pass def check_file(self, path): if not os.path.isfile(path): # sys.exit() return False else: return True def mk_file(self, path): with open(path, 'w', encoding="utf-8") as f: print("创建文件成功") pass def write(self, path, line): time.sleep(1) with open(path, 'a') as fileHandle: fileHandle.write(line + "\n") def read(self, path): result = [] with open(path, 'r', encoding="utf-8") as fileHandle: file_list = fileHandle.readlines() for i in file_list: temp = [i.replace("\t", ",").strip("\n")] result.append(temp) return result def remove_file(self, path): if self.check_file(path): os.remove(path) if __name__ == '__main__': pass ================================================ FILE: Base/BaseGetExcel.py ================================================ import xlrd import xlsxwriter from Base.BaseElementEnmu import Element from Base.BaseExcel import * from Base.BaseStatistics import readInfo def read_excel(file='c:/test.xls'): data = xlrd.open_workbook(file) table = data.sheet_by_index(0) nrows = table.nrows ncols = table.ncols colnames = table.row_values(0) # one rows data list = [] for rownum in range(1, nrows): row = table.row_values(rownum) if row: app = {} for i in range(len(colnames)): # row[i] = colnames[i] + row[i] app[colnames[i]] = row[i] list.append(app) return list def write_excel(): workbook = xlsxwriter.Workbook(Element.REPORT_FILE) worksheet2 = workbook.add_worksheet("测试详情") operateReport = OperateReport(workbook) operateReport.detail(worksheet2, readInfo(Element.INFO_FILE)) operateReport.close() if __name__ == "__main__": t = read_excel(Element.API_FILE) print(t) ================================================ FILE: Base/BaseIni.py ================================================ import configparser ''' 对ini文件的读写改 ''' class BaseIni(object): def __init__(self, path): self.cfg = configparser.ConfigParser() self.cfg.read(path) def read_ini(self): _pict = self.cfg.get("default", "pict") return True if _pict.lower() == 'true' else False def __write_ini(self): self.cfg.add_section("default1") self.cfg.set("default1", "title", "test msg") self.cfg.set("default1", "id", "test msg") self.cfg.add_section("ematter") self.cfg.set("ematter", "pages", 250) self.cfg.write(open('1.ini', "w")) def __edit_ini(self): self.cfg.set("default", "pict", "True") self.cfg.write(open('1.ini', "r+")) if __name__ == "__main__": from Base.BaseElementEnmu import Element t = BaseIni(Element.OPEN_PICT).read_ini() print(t) ================================================ FILE: Base/BaseInit.py ================================================ from Base.BaseFile import BaseFile from Base.BaseElementEnmu import Element class BaseInit(object): def __init__(self): self.bf = BaseFile() def mk_file(self): self.__destroy() self.bf.mk_file(Element.INFO_FILE) def __destroy(self): self.bf.remove_file(Element.INFO_FILE) ================================================ FILE: Base/BaseParams.py ================================================ import uuid from allpairspy import AllPairs # pip install allpairspy from collections import OrderedDict class BaseFuzzParams(object): """ 设置接口的逆向参数 自动生成模糊接口参数第一步,提前准备逆向场景 Args: d: dict类型,正向接口参数 Returns: dict Raises: 无 """ def __get_data(self, d): data = {} for i in d: data[i] = [] # 加入一般规则 data[i].append({"info": "正确的值", "code": 1, "value": d[i], "key": i}) data[i].append({"info": "为空", "code": -1, "value": "", "key": i}) data[i].append({"info": "错误的值", "code": -2, "value": self.__param_format(type(d[i])), "key": i}) data[i].append({"info": "删除", "code": -3, "key": i}) # 加入其它规则:如路径遍历,xss,注入 return data ''' 生成逆向场景参数 ''' def __param_format(self, key): if key == str: return str(uuid.uuid1()) elif key == int: return 963852 # 也可以使用随机整数的方式 elif key == list: return [str(uuid.uuid1())] elif key == dict: return {} elif key == "inject": return "t'exec master..xp_cmdshell 'nslookup www.google.com'--" # 路径遍历 elif key == "path_traversal": pass else: return "null" ''' 得到逆向场景参数后,用AllPairs生成全对偶参数 ''' def __set_fuzz(self, d): data = [] for i, par in enumerate(AllPairs(OrderedDict(d))): app = [] for j in par: app.append(j) data.append(app) dd = [] for i in data: d = [] for j in range(len(i)): d.append(i[j]) dd.append(d) d2 = [] for i in dd: d1 = [] for j in i: app = {} if j.get("code", -9) == -1: app[j["key"]] = "" elif j.get("code", -9) == -3: pass else: app[j["key"]] = j["value"] app["info"] = j["key"] + j["info"] d1.append(app) d2.append(d1) return d2 ''' 对外的函数,处理生成的对偶场景接口参数 Returns: [{},{}] ''' def param_fi(self, d): g_data = self.__get_data(d) s_fuzz = self.__set_fuzz(g_data) data = [] for i in s_fuzz: for j in range(len(i)): _info = "" for k in range(len(i)): _info = _info + "," + i[k]["info"] i[0].update(i[k]) i[0]["info"] = _info.strip(",") data.append(i[0]) break return data if __name__ == "__main__": fz = BaseFuzzParams().param_fi({"user": "name", "id": 1001, "pwd": "!@#$^&*", "data": {"test": "hello"}, "my_list":["1", "2"]}) print(fz) ================================================ FILE: Base/BaseReq.py ================================================ import requests import json import ast from Base.BaseElementEnmu import Element from Base.BaseParams import BaseFuzzParams from Base.BaseStatistics import writeInfo class Config(object): def __init__(self): pass def config_req(self, kw): app = {} header = {"Accept": "*/*", "Content-Type": "application/json;charset=utf-8"} for item in kw: url = "%s://%s" % (item["protocol"], item["url"]) print("==请求url:%s" % url) print("==请求参数:%s" % item["params"]) params = "{}" if item.get("params"): params = item["params"] if item["method"] == "get": res = requests.get(url, data=json.dumps(ast.literal_eval(params)), headers=header, verify=False) elif item["method"] == "post": res = requests.post(url, data=json.dumps(ast.literal_eval(params)), headers=header, verify=False) else: print("现在只针post和ge方法进行了测试,其他方法请自行扩展") app["url"] = item["url"] app["method"] = item["method"] app["params"] = item["params"] app["code"] = str(res.status_code) app["msg"] = item["mark"] app["hope"] = item.get("hope", "") app["res"] = str(res.text) print("==响应结果=:%s=" % app["res"]) app["ress"] = res # 传给检查函数进行解析 app["result"] = self.__check(app["hope"], app["ress"]) print("==响应码=:%s=" % app["code"]) writeInfo(app, Element.INFO_FILE) def config_req_pict(self, kw, req=None): app = {} header = {"Accept": "*/*", "Content-Type": "application/json;charset=utf-8"} for item in kw: url = "%s://%s" % (item["protocol"], item["url"]) # 如果有参数才做模糊测试,没有做正向场景测试 if item.get("params"): print("进行逆向场景测试") params = BaseFuzzParams().param_fi(ast.literal_eval(item["params"])) for i in params: _info = "" if i.get("info", "null") != "null": _info = i.get("info", "参数正确") i.pop("info") if item["method"] == "get": res = requests.get(url, data=json.dumps(i), headers=header) else: res = requests.post(url, data=json.dumps(i), headers=header) app["url"] = item["url"] app["method"] = item["method"] app["params"] = str(i) app["code"] = str(res.status_code) app["msg"] = item["mark"] + "_" + _info # app["hope"] = item.get("hope", "") app["hope"] = "" app["res"] = str(res.text) app["result"] = "" print("请求url:%s" % url) print("请求参数:%s" % app["params"]) print("响应码:%s" % app["code"]) print("响应结果:%s" % app["res"]) writeInfo(app, Element.INFO_FILE) else: self.config_req(kw) def __check(self, hope, res): resp = json.dumps(json.loads(res.text), separators=(',', ':')) is_check = 0 # 0表示期望值不存在,没有进行检查;1成功;-1失败 hopes = hope.split("|") if len(hopes) and len(hope): is_check = 1 # 循环检查期望值是否在实际值中能找到 for j in hopes: if resp.find(j) == -1: is_check = -1 break if is_check == 0: return "未检查" elif is_check == 1: return "成功" else: return "失败" ================================================ FILE: Base/BaseReq1.py ================================================ import requests import json import ast from Base.BaseElementEnmu import Element from Base.BaseParams import BaseFuzzParams from Base.BaseStatistics import writeInfo class Config(object): def __init__(self, sessions): self.sessions = sessions def config_req(self, kw): app = {} header = {"Accept": "*/*", "Content-Type": "application/json;charset=utf-8"} for item in kw: url = "%s://%s" % (item["protocol"], item["url"]) print("==请求url:%s" % url) print("==请求参数:%s" % item["params"]) params = "{}" if item.get("params"): params = item.get("params") if item["method"] == "get": res = self.sessions.get(url, data=json.dumps(ast.literal_eval(params)), headers=header, verify=False) elif item["method"] == "post": res = self.sessions.post(url, data=json.dumps(ast.literal_eval(params)), headers=header, verify=False) else: print("现在只针post和ge方法进行了测试,其他方法请自行扩展") app["url"] = item["url"] app["method"] = item["method"] app["params"] = item["params"] app["code"] = str(res.status_code) app["msg"] = item["mark"] app["hope"] = item.get("hope", "") app["res"] = str(res.text) app["ress"] = res # 传给检查函数进行解析 print("==响应结果:%s=" % app["res"]) app["result"] = self.__check(app["hope"], app["ress"]) print("==响应码:%s=" % app["code"]) writeInfo(app, Element.INFO_FILE) def config_req_pict(self, kw, req=None): app = {} header = {"Accept": "*/*", "Content-Type": "application/json;charset=utf-8"} for item in kw: url = "%s://%s" % (item["protocol"], item["url"]) # 如果有参数才做模糊测试,没有做正向场景测试 if item.get("params"): print("进行逆向场景测试") params = BaseFuzzParams().param_fi(ast.literal_eval(item["params"])) for i in params: _info = "" if i.get("info", "null") != "null": _info = i.get("info", "参数正确") i.pop("info") if item["method"] == "get": res = self.sessions.get(url, data=json.dumps(i), headers=header) else: res = self.sessions.post(url, data=json.dumps(i), headers=header) app["url"] = item["url"] app["method"] = item["method"] app["params"] = str(i) app["code"] = str(res.status_code) app["msg"] = item["mark"] + "_" + _info # app["hope"] = item.get("hope", "") app["hope"] = "" app["res"] = str(res.text) app["result"] = "" print("请求url:%s" % url) print("请求参数:%s" % app["params"]) print("响应码:%s" % app["code"]) print("响应结果:%s" % app["res"]) writeInfo(app, Element.INFO_FILE) else: self.config_req(kw) def __check(self, hope, res): resp = json.dumps(json.loads(res.text), separators=(',', ':')) is_check = 0 # 0表示期望值不存在,没有进行检查;1成功;-1失败 hopes = hope.split("|") if len(hopes) and len(hope): is_check = 1 # 循环检查期望值是否在实际值中能找到 for j in hopes: if resp.find(j) == -1: is_check = -1 break if is_check == 0: return "未检查" elif is_check == 1: return "成功" else: return "失败" ================================================ FILE: Base/BaseRunner.py ================================================ # -*- coding: utf-8 -*- import unittest import requests # 登录 def get_session(): req = requests.session() url = "" data = {} req.post(url, data, verify=False) return req class ParametrizedTestCase(unittest.TestCase): """ TestCase classes that want to be parametrized should inherit from this class. """ def __init__(self, methodName='runTest', param=None): super(ParametrizedTestCase, self).__init__(methodName) @classmethod def setUpClass(cls): # cls.rq = get_session() # 登录后的session pass @classmethod def tearDownClass(cls): pass @staticmethod def parametrize(testcase_klass, param=None): testloader = unittest.TestLoader() testnames = testloader.getTestCaseNames(testcase_klass) suite = unittest.TestSuite() for name in testnames: suite.addTest(testcase_klass(name, param=param)) return suite ================================================ FILE: Base/BaseRunner1.py ================================================ # -*- coding: utf-8 -*- import unittest import requests # 登录 def get_session(): req = requests.session() url = "http://127.0.0.1:8000/myapi/login/" data = {"username": "test1", "pwd": "1234567"} req.post(url, data, verify=False) return req class ParametrizedTestCase(unittest.TestCase): """ TestCase classes that want to be parametrized should inherit from this class. """ def __init__(self, methodName='runTest', param=None): super(ParametrizedTestCase, self).__init__(methodName) @classmethod def setUpClass(cls): cls.sessions = get_session() # 登录后的session @classmethod def tearDownClass(cls): pass @staticmethod def parametrize(testcase_klass, param=None): testloader = unittest.TestLoader() testnames = testloader.getTestCaseNames(testcase_klass) suite = unittest.TestSuite() for name in testnames: suite.addTest(testcase_klass(name, param=param)) return suite ================================================ FILE: Base/BaseStatistics.py ================================================ import pickle def readInfo(path): data = [] with open(path, 'rb') as f: try: data = pickle.load(f) print(data) except EOFError: data = [] # print("读取文件错误") # print("------read-------") # print(data) return data def writeInfo(kw, path="data.pickle"): """ :type data: dict """ data = {"result": kw["result"], "hope": kw["hope"], "msg": kw["msg"], "url": kw["url"], "params": kw["params"] ,"code": kw["code"], "method": kw["method"], "res": kw['res']} _read = readInfo(path) result = [] if _read: _read.append(data) result = _read else: result.append(data) with open(path, 'wb') as f: pickle.dump(result, f) ================================================ FILE: Base/__init__.py ================================================ ================================================ FILE: Log/param.txt ================================================ ================================================ FILE: Log/param_result.txt ================================================ ================================================ FILE: README.md ================================================ # Ŀ python3Զӿڲ ## * Win7 64python 3Pycharm. unittest * excel * ʼͲԽ * pictģ ## ÷ ### ʹģ * ȵҪpython3+Ļ * άReportĿ¼µapi.xlsxдӿڲ * Runner.pystart.bat,python runner.py * 鿴ԱReportĿ¼µreport.xlsx ### ʹģ * SettingĿ¼µConfig.iniΪTrue * ģֶֻ֧ÿĴɾijչ * ģݲּ֧ ## ![](img/api.jpg "api.jpg") ![ʹģԺIJԱ](img/pict.jpg "pict.jpg") ![ûʹģԵIJԱ](img/no_pict.jpg "no_pict.jpg") ## * [˵](channel_log.md) ================================================ FILE: Runner/__init__.py ================================================ ================================================ FILE: Runner/runner.py ================================================ # -*- coding:utf-8 -*- import sys sys.path.append("..") import unittest from TestCases.Api import ApiTest from Base.BaseRunner import ParametrizedTestCase from Base.BaseGetExcel import write_excel from Base.BaseInit import BaseInit def runner_case(): BaseInit().mk_file() suite = unittest.TestSuite() suite.addTest(ParametrizedTestCase.parametrize(ApiTest)) unittest.TextTestRunner(verbosity=2).run(suite) if __name__ == '__main__': runner_case() write_excel() ================================================ FILE: Runner/runner1.py ================================================ # -*- coding:utf-8 -*- import sys sys.path.append("..") import unittest from TestCases.Api1 import ApiTest from Base.BaseRunner1 import ParametrizedTestCase from Base.BaseGetExcel import write_excel from Base.BaseInit import BaseInit def runner_case(): BaseInit().mk_file() suite = unittest.TestSuite() suite.addTest(ParametrizedTestCase.parametrize(ApiTest)) unittest.TextTestRunner(verbosity=2).run(suite) if __name__ == '__main__': runner_case() write_excel() ================================================ FILE: Runner/start_test.bat ================================================ @ECHO OFF python runner.py ECHO.[ EXIT ] press any key... PAUSE>nul ================================================ FILE: Setting/Config.ini ================================================ [default] pict = False ================================================ FILE: TestCases/Api.py ================================================ from Base.BaseRunner import ParametrizedTestCase from Base.BaseGetExcel import read_excel from Base.BaseReq import Config from Base.BaseElementEnmu import Element from Base.BaseIni import BaseIni class ApiTest(ParametrizedTestCase): def test_api(self): ls = read_excel(Element.API_FILE) if BaseIni(Element.OPEN_PICT).read_ini(): Config().config_req_pict(ls) else: Config().config_req(ls) @classmethod def setUpClass(cls): super(ApiTest, cls).setUpClass() # cls.req ================================================ FILE: TestCases/Api1.py ================================================ from Base.BaseRunner1 import ParametrizedTestCase from Base.BaseGetExcel import read_excel from Base.BaseReq1 import Config from Base.BaseElementEnmu import Element from Base.BaseIni import BaseIni class ApiTest(ParametrizedTestCase): def test_api(self): ls = read_excel(Element.API_FILE) if BaseIni(Element.OPEN_PICT).read_ini(): Config(self.sessions).config_req_pict(ls) else: Config(self.sessions).config_req(ls) @classmethod def setUpClass(cls): super(ApiTest, cls).setUpClass() ================================================ FILE: TestCases/__init__.py ================================================ ================================================ FILE: channel_log.md ================================================ # 2021-3-16 * ģȥpict * ½Ľӿʹsession󣬴Ϊrunner1.py * api.xlsxļеļ޸ĸʽΪ - ```"msg":"success"``` - ```"code":1|"msg":"success"``` # 2018-6-9 * ӿڲȫع * excel * pictģ ================================================ FILE: requirements.txt ================================================ requests==2.24.0 XlsxWriter==1.3.7 xlrd==1.2.0 allpairspy==2.5.0