├── core ├── __init__.py ├── log.py ├── config.py ├── mysql.py └── request.py ├── function ├── __init__.py └── common.py ├── report ├── docs │ └── index.md └── mkdocs.yml ├── case └── user.ini ├── run.py ├── constants.py ├── .gitignore └── README.md /core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /function/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /report/docs/index.md: -------------------------------------------------------------------------------- 1 | # 欢迎来到测试报告 2 | -------------------------------------------------------------------------------- /report/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: TezignAPI Test Report 2 | dev_addr: 0.0.0.0:8000 3 | site_dir: /site 4 | theme: readthedocs 5 | 6 | pages: 7 | - [index.md, Home] -------------------------------------------------------------------------------- /case/user.ini: -------------------------------------------------------------------------------- 1 | [测试报告] 2 | report = '用户' 3 | reportName = 'user测试报告' 4 | 5 | [user_login] 6 | number = 1 7 | name = 登录 8 | method = post 9 | url = /user/login 10 | data = 'username=xxxxxxx&password=xxxxxx' 11 | headers = {'Content-Type':'application/x-www-form-urlencoded'} 12 | code = 0 -------------------------------------------------------------------------------- /core/log.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | # author: 赫本z 4 | # 基础包: 日志服务 5 | import logging 6 | 7 | def get_logger(): 8 | global logPath 9 | try: 10 | logPath 11 | except NameError: 12 | logPath = "" 13 | FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' 14 | logging.basicConfig(level=logging.INFO, format=FORMAT) 15 | return logging -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | # 执行包:runscript 4 | 5 | import function.common as func 6 | 7 | ApiTest = func.ApiTest() 8 | 9 | FILENAME = 'user.ini' 10 | 11 | 12 | """1.新建测试报告目录""" 13 | ApiTest.reset_report(filename=func.cs.CASE_PATH+FILENAME) 14 | 15 | """2.执行测试用例""" 16 | ApiTest.run_test(filename=func.cs.CASE_PATH+FILENAME) 17 | 18 | """3.统计测试报告结果""" 19 | ApiTest.write_report_result() 20 | -------------------------------------------------------------------------------- /core/config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | # author: 赫本z 4 | # 基础包:配置服务 5 | 6 | import ConfigParser 7 | import core.log as log 8 | 9 | config = ConfigParser.ConfigParser() 10 | logging = log.get_logger() 11 | 12 | def get_config(filename): 13 | """ 14 | 获取文件配置 15 | :param filename: 配置文件名 16 | :return: None 17 | """ 18 | global config 19 | try: 20 | config.read(filename) 21 | return True 22 | except Exception, e: 23 | logging.error("读取配置失败 %s" % e) 24 | 25 | 26 | def get_data(title, key): 27 | """ 28 | 参数配置 29 | :param title: 配置文件的头信息 30 | :param key: 配置文件的key值 31 | :return: 配置文件的value 32 | """ 33 | try: 34 | value = config.get(title, key) 35 | return value 36 | except Exception, e: 37 | logging.error("获取参数失败 %s" % e) 38 | 39 | 40 | def get_title_list(): 41 | """ 42 | 获取所有title 43 | :return: title list 44 | """ 45 | try: 46 | title = config.sections() 47 | return str(title).decode("string_escape") 48 | # return '\n'.join(title) 49 | except Exception, e: 50 | logging.error("获取title信息失败 %s", e) 51 | 52 | 53 | -------------------------------------------------------------------------------- /core/mysql.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | # author: 赫本z 4 | # 基础包: MySQL 5 | 6 | import pymysql.cursors 7 | import core.log as log 8 | 9 | 10 | logging = log.get_logger() 11 | conn = None 12 | 13 | def connect(host, user, password, db, charset='utf8'): 14 | """ 15 | 链接Mysql 16 | :param host: 地址 17 | :param user: 用户 18 | :param password: 密码 19 | :param db: 数据库名 20 | :param charset: 数据类型 21 | :return: 链接 22 | """ 23 | global conn 24 | if conn == None: 25 | conn = pymysql.connect(host=host, 26 | user=user, 27 | password=password, 28 | db=db, 29 | charset=charset, 30 | cursorclass=pymysql.cursors.DictCursor) 31 | return conn 32 | 33 | 34 | def execute(sql): 35 | """ 36 | 执行SQL 37 | :param sql: 执行的SQL 38 | :return: 影响行数 39 | """ 40 | global conn 41 | try: 42 | with conn.cursor() as cursor: 43 | res = cursor.execute(sql) 44 | conn.commit() 45 | # 这里一定要写commit 不然提交的sql 都会被事务回滚 46 | return res 47 | except Exception, e: 48 | logging.error("sql is empty or error %s" % e) 49 | 50 | 51 | def close(): 52 | """ 53 | 关闭MySQL连接 54 | :return: None 55 | """ 56 | global conn 57 | conn.close() 58 | -------------------------------------------------------------------------------- /constants.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | # 脚本功能:全部变量 4 | 5 | import sys 6 | import time 7 | import os 8 | reload(sys) 9 | sys.setdefaultencoding('utf8') 10 | 11 | TEST_URL = 'http://127.0.0.1:8080' 12 | OUT_PATH = os.path.dirname(os.path.dirname(__file__)) 13 | 14 | REPORT_NAME = '测试报告' 15 | TITLE = '所有数据准备SQL' 16 | 17 | METHOD = 'method' 18 | URL = 'url' 19 | DATA = 'data' 20 | NAME = 'name' 21 | NUMBER = 'number' 22 | CODE = 'code' 23 | HEADERS = 'headers' 24 | REPORT = 'report' 25 | R_NAME = 'reportName' 26 | 27 | REPORT_PATH = OUT_PATH + "/api4code/report/docs/" 28 | YML_REPORT = OUT_PATH + "/api4code/report/mkdocs.yml" 29 | 30 | 31 | CASE_PATH = OUT_PATH + "/api4code/case/" 32 | 33 | #测试报告内容 34 | API_TEST_FAIL = """ 35 | ``` 36 | %s Case Fail 37 | Number: %s 38 | Method: %s 39 | Url: %s 40 | Headers: 41 | %s 42 | Data : 43 | %s 44 | 期望值 : %s 45 | 实际值 : %s 46 | ``` 47 | """ 48 | 49 | API_TEST_SUCCESS = """ 50 | ``` 51 | %s Case Pass 52 | Number: %s 53 | Method: %s 54 | Url: %s 55 | Headers: 56 | %s 57 | Data : 58 | %s 59 | 期望值 : %s 60 | 实际值 : %s 61 | ``` 62 | """ 63 | 64 | #报告结果统计 65 | RESULT_CONTENT = """ 66 | 测试结果如下: 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
AllPassFail
%s%s%s
79 | """ 80 | 81 | NOW = '_' + time.strftime('%Y%m%d', time.localtime(time.time())) + '.md' 82 | PROJECT_TIME = time.strftime('%Y%m%d', time.localtime(time.time())) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | .hypothesis/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | .static_storage/ 58 | .media/ 59 | local_settings.py 60 | 61 | # Flask stuff: 62 | instance/ 63 | .webassets-cache 64 | 65 | # Scrapy stuff: 66 | .scrapy 67 | 68 | # Sphinx documentation 69 | docs/_build/ 70 | 71 | # PyBuilder 72 | target/ 73 | 74 | # Jupyter Notebook 75 | .ipynb_checkpoints 76 | 77 | # pyenv 78 | .python-version 79 | 80 | # celery beat schedule file 81 | celerybeat-schedule 82 | 83 | # SageMath parsed files 84 | *.sage.py 85 | 86 | # Environments 87 | .env 88 | .venv 89 | env/ 90 | venv/ 91 | ENV/ 92 | env.bak/ 93 | venv.bak/ 94 | 95 | # Spyder project settings 96 | .spyderproject 97 | .spyproject 98 | 99 | # Rope project settings 100 | .ropeproject 101 | 102 | # mkdocs documentation 103 | /site 104 | 105 | # mypy 106 | .mypy_cache/ 107 | 108 | /.idea -------------------------------------------------------------------------------- /core/request.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | #-*- coding: UTF-8 -*- 3 | # 基础包:接口测试的封装 4 | 5 | import requests 6 | import core.log as log 7 | import json 8 | 9 | logging = log.get_logger() 10 | 11 | def change_type(value): 12 | """ 13 | 对dict类型进行中文识别 14 | :param value: 传的数据值 15 | :return: 转码后的值 16 | """ 17 | try: 18 | if isinstance(eval(value), str): 19 | return value 20 | if isinstance(eval(value), dict): 21 | result = eval(json.dumps(value)) 22 | return result 23 | except Exception, e: 24 | logging.error("类型问题 %s", e) 25 | 26 | 27 | def api(method, url, data ,headers): 28 | """ 29 | 自定义一个接口测试的方法 30 | :param method: 请求类型 31 | :param url: 地址 32 | :param data: 数据 33 | :param headers: 请求头 34 | :return: code码 35 | """ 36 | global results 37 | try: 38 | if method == ("post" or "POST"): 39 | results = requests.post(url, data, headers=headers) 40 | if method == ("get" or "GET"): 41 | results = requests.get(url, data, headers=headers) 42 | # if method == "put": 43 | # results = requests.put(url, data, headers=headers) 44 | # if method == "delete": 45 | # results = requests.delete(url, headers=headers) 46 | # if method == "patch": 47 | # results == requests.patch(url, data, headers=headers) 48 | # if method == "options": 49 | # results == requests.options(url, headers=headers) 50 | response = results.json() 51 | code = response.get("code") 52 | return code 53 | except Exception, e: 54 | logging.error("service is error", e) 55 | 56 | 57 | def content(method, url, data, headers): 58 | """ 59 | 请求response自己可以自定义检查结果 60 | :param method: 请求类型 61 | :param url: 请求地址 62 | :param data: 请求参数 63 | :param headers: 请求headers 64 | :return: message信息 65 | """ 66 | global results 67 | try: 68 | if method == ("post" or "POST"): 69 | results = requests.post(url, data, headers=headers) 70 | if method == ("get" or "GET"): 71 | results = requests.get(url, data, headers=headers) 72 | if method == ("put" or "PUT"): 73 | results = requests.put(url, data, headers=headers) 74 | if method == ("patch" or "PATCH"): 75 | results = requests.patch(url, data, headers=headers) 76 | response = results.json() 77 | message = response.get("message") 78 | result = response.get("result") 79 | content = {"message": message, "result": result} 80 | return content 81 | except Exception, e: 82 | logging.error("请求失败 %s" % e) 83 | -------------------------------------------------------------------------------- /function/common.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | # 业务包:通用函数 4 | 5 | 6 | import core.mysql as mysql 7 | import core.log as log 8 | import core.request as request 9 | import core.config as conf 10 | import constants as cs 11 | import os 12 | 13 | logging = log.get_logger() 14 | 15 | 16 | class ApiTest: 17 | """接口测试业务类""" 18 | 19 | def __init__(self): 20 | pass 21 | 22 | def prepare_data(self, host, user, password, db, sql): 23 | """ 24 | 数据准备,添加测试数据 25 | :param host: 服务地址 26 | :param user: 用户 27 | :param password: 密码 28 | :param db: 数据库名 29 | :param sql: 执行的SQL 30 | :return: 31 | """ 32 | mysql.connect(host, user, password, db) 33 | res = mysql.execute(sql) 34 | mysql.close() 35 | logging.info("Run sql: the row number affected is %s" % res) 36 | return res 37 | 38 | def get_prepare_sql(self, filename, key): 39 | """ 40 | 获取预备执行的SQL 41 | :param title: 配置文件头信息 42 | :param key: 配置文件值 43 | :return: Value 44 | """ 45 | try: 46 | conf.get_config(filename) 47 | value = conf.get_data(title=cs.TITLE, key=key) 48 | return value 49 | except Exception, e: 50 | logging.error("获取用例参数值失败 %s" % e) 51 | 52 | def reset_report(self, filename): 53 | """ 54 | 这个方法主要是通过写入文件的方法,先打开cs.YML_REPORT也就是 55 | mkdocs.yml文件,判断文件中是否存在当前写入的内容。 56 | :param filename: 测试用例文件 57 | :return: 测试报告内容 58 | """ 59 | try: 60 | result = os.path.exists(cs.REPORT_PATH) 61 | if result == True: 62 | conf.get_config(filename) 63 | reportName = eval(conf.get_data(title=cs.REPORT_NAME, key=cs.REPORT)) 64 | report_name = eval(conf.get_data(title=cs.REPORT_NAME, key=cs.R_NAME)) 65 | file = open(cs.YML_REPORT, 'r') 66 | list_con = file.readlines() 67 | content = str(list_con).decode("string_escape") 68 | fileContent = "- [%s, %s]" 69 | row = "\n" 70 | _content = fileContent % (reportName + cs.NOW, report_name) 71 | con = row + _content 72 | 73 | if fileContent % (reportName + cs.NOW, report_name) not in content: 74 | f = open(cs.YML_REPORT, 'a+') 75 | f.write(con) 76 | else: 77 | logging.info("内容已经存在 %s" % _content) 78 | except Exception, e: 79 | logging.error("文件路径不存在 %s", e) 80 | 81 | def write_report(self, content): 82 | """ 83 | 这个方法用于书写测试报告从而解决之前的通过 84 | logging方式写入导致其他的日志无法实现写入 85 | :param content: 传入文件的内容 86 | :return: None 87 | """ 88 | reportName = eval(conf.get_data(title=cs.REPORT_NAME, key=cs.REPORT)) 89 | _reportName = reportName + cs.NOW 90 | filename = cs.REPORT_PATH + _reportName 91 | try: 92 | file = open(filename, 'a+') 93 | file.writelines(content) 94 | except Exception, e: 95 | logging.error("文件路径不存在 %s", e) 96 | 97 | def execute_case(self, filename): 98 | """ 99 | 执行接口测试用例的方法 100 | :param filename: 用例文件名称 101 | :return: 测试结果 102 | """ 103 | conf.get_config(filename) 104 | list = eval(conf.get_title_list()) 105 | try: 106 | for i in range(1, len(list)): 107 | title = list[i] 108 | number = conf.get_data(title, key=cs.NUMBER) 109 | name = conf.get_data(title, key=cs.NAME) 110 | method = conf.get_data(title, key=cs.METHOD) 111 | url = conf.get_data(title, key=cs.URL) 112 | data = eval(conf.get_data(title, key=cs.DATA)) 113 | _data = request.json.dumps(data,ensure_ascii=False,indent=4) 114 | headers = eval(conf.get_data(title, key=cs.HEADERS)) 115 | _headers = request.json.dumps(headers,ensure_ascii=False,indent=4) 116 | testUrl = cs.TEST_URL + url 117 | actualCode = request.api(method, testUrl, _data, headers) 118 | expectCode = conf.get_data(title, key=cs.CODE) 119 | 120 | if actualCode != expectCode: 121 | logging.info("新增一条接口失败报告") 122 | self.write_report( 123 | cs.API_TEST_FAIL % (name, number, method, testUrl, _headers,_data, expectCode, actualCode)) 124 | else: 125 | logging.info("新增一条接口成功报告") 126 | self.write_report(cs.API_TEST_SUCCESS % (name, number, method, testUrl, _headers,_data, expectCode, actualCode)) 127 | except Exception,e: 128 | logging.error('执行case失败 %s',e) 129 | 130 | def run_test(self, filename): 131 | """ 132 | 普通接口测试类方法 133 | :param filename: 接口的用例name 134 | :return: 测试报告 135 | """ 136 | reportName = eval(conf.get_data(title=cs.REPORT_NAME, key=cs.REPORT)) 137 | _filename = cs.REPORT_PATH + reportName + cs.NOW 138 | try: 139 | if os.path.exists(_filename): 140 | os.remove(_filename) 141 | self.execute_case(filename) 142 | else: 143 | self.execute_case(filename) 144 | except Exception, e: 145 | logging.error("执行接口测试失败 %s", e) 146 | 147 | def write_report_result(self): 148 | """ 149 | 这个方法用于书写测试报告结果 150 | :return: None 151 | """ 152 | reportName = eval(conf.get_data(title=cs.REPORT_NAME, key=cs.REPORT)) 153 | _filename = cs.REPORT_PATH + reportName + cs.NOW 154 | try: 155 | f = file(_filename) 156 | content = f.read() 157 | if content != None: 158 | _count = content.count("Number") 159 | _fail = content.count("Case Fail") 160 | _pass = content.count("Case Pass") 161 | space = content.split('\n') 162 | space.insert(0,cs.RESULT_CONTENT % (_count, _pass, _fail)) 163 | _content_ = '\n'.join(space) 164 | fp = file(_filename,'r+') 165 | fp.write(_content_) 166 | except Exception, e: 167 | logging.error("文件路径不存在 %s", e) 168 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 代码编写用例和接口测试 2 | 3 | **公司新来两个妹子一直吐槽,这个接口测试用例用excel维护起来十分费脑费事,而且比较low(内心十分赞同但是不能推翻自己),妹子希望只在编辑器中就能完成所有工作,包括用例编辑、场景设计、数据处理、一键自动化测试、报告生成,于是偷偷的进行了二次改版。** 4 | 5 | 变更内容如下: 6 | 7 | * ###### 1.代码结构 8 | 9 | ![image.png](http://upload-images.jianshu.io/upload_images/2955280-4b7c7c7ab5a756ce.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/440) 10 | 11 | * ###### 2.新增测试报告网页版和版本管理 12 | * ###### 3.新增用例代码化 13 | 14 | 15 | ##### 一、封装一个获取用例的模块 16 | 17 | ![image.png](http://upload-images.jianshu.io/upload_images/2955280-f7b9015622bf7e57.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1200) 18 | 19 | > ###### 用例的写法可以按照yml文件的写法,后缀的文件都可为.conf、.config、.ini。[]中的是测试用例场景,下面的参数内容对应接口用例参数。 20 | > 21 | > ###### 简单介绍下python内置模块ConfigParser: 22 | > - ConfigParser 是用来读取配置文件的包。配置文件的格式如下:中括号“[ ]”内包含的为section。section 下面为类似于key:value 的配置内容。(key = value也可以具体方法这次不详细展开,之后写一遍关于ConfigParser的用法,懂原理会让工作更轻松。) 23 | > 24 | > - 这里讲讲为什么配置写在最外层,如果写到文件夹中,怎么都无法读取配置。python执行run命令的时候需要.ini文件跟run 文件在同个文件夹下。所以应该是路径问题导致,之后尝试修复这个BUG。 25 | 26 | (通过操作绝对路径的方法修复此BUG上图已经修复) 27 | 28 | 29 | ###### 这次变更代码实现如下: 30 | ```python 31 | #!/usr/bin/python 32 | # -*- coding: UTF-8 -*- 33 | # 基础包:配置服务 34 | 35 | import ConfigParser 36 | 37 | config = ConfigParser.ConfigParser() 38 | 39 | 40 | def get_config(filename): 41 | """ 42 | 获取文件配置 43 | :param filename: 配置文件名 44 | :return: None 45 | """ 46 | global config 47 | try: 48 | config.read(filename) 49 | return True 50 | except Exception, e: 51 | print ("读取配置失败 %s" % e) 52 | 53 | 54 | def get_data(title, key): 55 | """ 56 | 参数配置 57 | :param title: 配置文件的头信息 58 | :param key: 配置文件的key值 59 | :return: 配置文件的value 60 | """ 61 | try: 62 | value = config.get(title, key) 63 | return value 64 | except Exception, e: 65 | print ("获取参数失败 %s" % e) 66 | 67 | 68 | def get_title_list(): 69 | """ 70 | 获取所有title 71 | :return: title list 72 | """ 73 | try: 74 | title = config.sections() 75 | return str(title).decode("string_escape") 76 | except Exception, e: 77 | print ("获取title信息失败 %s", e) 78 | ``` 79 | 80 | 81 | #### 二、封装一个日志的模块 82 | 83 | > ###### 这次日志进行了一次更改:会将测试用例返回结果文件内容写入,文件通过mkdocs生成测试报告。 84 | > 85 | > ###### 公司用的微服务,作为testOps所以需要对Docker有一定涉猎,docker.hub官方提供了mkdocs的镜像。拉取官网镜像,将数据卷挂载到搭载测试报告的宿主机上,就可以访问了。你只要维护代码的测试用例,自动更新测试报告。 86 | 看下展示效果: 87 | 88 | ![image.png](http://upload-images.jianshu.io/upload_images/2955280-56d2b3383a2521b6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 89 | 90 | 91 | 代码如下: 92 | ```python 93 | #!/usr/bin/python 94 | # -*- coding: UTF-8 -*- 95 | # 基础包:日志服务 96 | 97 | import logging 98 | import constants as cs 99 | import logging.handlers 100 | 101 | 102 | def get_logger(name='report'): 103 | FORMAT = '%(message)s' 104 | filename = cs.REPORT_PATH + name + cs.NOW 105 | logging.basicConfig(level=logging.WARNING, format=FORMAT, 106 | filename=filename, filemode='w') 107 | return logging 108 | ``` 109 | 110 | 111 | #### 三、调用接口的requests 112 | 代码如下: 113 | ```python 114 | #!/usr/bin/python 115 | # -*- coding: UTF-8 -*- 116 | # 基础包:接口测试的封装 117 | 118 | import requests 119 | import json 120 | 121 | 122 | def change_type(value): 123 | """ 124 | 对dict类型进行中文识别 125 | :param value: 传的数据值 126 | :return: 转码后的值 127 | """ 128 | result = eval(json.dumps(value, ensure_ascii=False, encoding="UTF-8")) 129 | return result 130 | 131 | 132 | def api(method, url, data, headers): 133 | """ 134 | 定义一个请求接口的方法和需要的参数 135 | :param method: 请求类型 136 | :param url: 请求地址 137 | :param data: 请求参数 138 | :param headers: 请求headers 139 | :return: code码 140 | """ 141 | global results 142 | try: 143 | if method == ("post" or "POST"): 144 | results = requests.post(url, data, headers=headers) 145 | if method == ("get" or "GET"): 146 | results = requests.get(url, data, headers=headers) 147 | response = results.json() 148 | code = response.get("code") 149 | return code 150 | except Exception, e: 151 | print ("请求失败 %s" % e) 152 | ``` 153 | 154 | #### 四、业务包调用封装包(common.py) 155 | ```python 156 | #!/usr/bin/python 157 | # -*- coding: UTF-8 -*- 158 | # 业务包:通用函数 159 | 160 | 161 | import lib.tezMysql as mysql 162 | import lib.tezLog as log 163 | import lib.tezRequest as request 164 | import lib.tezConfig as conf 165 | import constants as cs 166 | import os 167 | 168 | def prepare_data(host, user, password, db, sql): 169 | """ 170 | 数据准备,添加测试数据 171 | :param host: 服务地址 172 | :param user: 用户 173 | :param password: 密码 174 | :param db: 数据库名 175 | :param sql: 执行的SQL 176 | :return: 177 | """ 178 | mysql.connect(host, user, password, db) 179 | res = mysql.execute(sql) 180 | mysql.close() 181 | print ("Run sql: the row number affected is %s" % res) 182 | return res 183 | 184 | 185 | def get_prepare_sql(filename, key): 186 | """ 187 | 获取预备执行的SQL 188 | :param title: 配置文件头信息 189 | :param key: 配置文件值 190 | :return: Value 191 | """ 192 | try: 193 | conf.get_config(filename) 194 | value = conf.get_data(title=cs.TITLE, key=key) 195 | return value 196 | except Exception, e: 197 | print ("获取用例参数值失败 %s" % e) 198 | 199 | 200 | def reset_report(filename): 201 | try: 202 | result = os.path.exists(cs.REPORT_PATH) 203 | if result == True: 204 | conf.get_config(filename) 205 | reportName = eval(conf.get_data(title=cs.REPORT_NAME, key=cs.REPORT)) 206 | report_name = eval(conf.get_data(title=cs.REPORT_NAME, key=cs.R_NAME)) 207 | file = open(cs.YML_REPORT, 'r') 208 | list_con = file.readlines() 209 | content = str(list_con).decode("string_escape") 210 | fileContent = "- [%s, %s]" 211 | row = "\n" 212 | con = row + fileContent % (reportName + cs.NOW, report_name) 213 | 214 | if fileContent % (reportName + cs.NOW, report_name) not in content: 215 | f = open(cs.YML_REPORT, 'a+') 216 | f.write(con) 217 | else: 218 | print ("内容已经存在 %s" % con) 219 | except Exception, e: 220 | print ("文件路径不存在 %s", e) 221 | 222 | 223 | def run_test(filename): 224 | conf.get_config(filename) 225 | list = eval(conf.get_title_list()) 226 | reportName = eval(conf.get_data(cs.REPORT_NAME, key=cs.REPORT)) 227 | logging = log.get_logger(reportName) 228 | for i in range(2, len(list)): 229 | title = list[i] 230 | number = eval(conf.get_data(title, key=cs.NUMBER)) 231 | name = str(conf.get_data(title, key=cs.NAME)) 232 | method = str(conf.get_data(title, key=cs.METHOD)) 233 | url = str(conf.get_data(title, key=cs.URL)) 234 | data = request.change_type(conf.get_data(title, key=cs.DATA)) 235 | headers = eval(conf.get_data(title, key=cs.HEADERS)) 236 | testUrl = cs.TEST_URL + url 237 | actualCode = request.api(method, testUrl, data, headers) 238 | expectCode = conf.get_data(title, key=cs.CODE) 239 | 240 | 241 | if actualCode != expectCode: 242 | print "FailInfo" 243 | print number 244 | logging.warning("- FailCase : %s", name) 245 | logging.warning(" - Number : %s", number) 246 | logging.warning(" - Method : %s", method) 247 | logging.warning(" - Url : %s", testUrl) 248 | logging.warning(" - Data :
``` %s ```", data) 249 | logging.warning(" - Headers :
``` %s ```", headers) 250 | logging.warning(" - 期望值 : %s", expectCode) 251 | logging.warning(" - 实际值 : %s", str(actualCode)) 252 | logging.warning("*****************") 253 | else: 254 | print number 255 | print "TrueInfo" 256 | logging.warning("- TrueCase %s", name) 257 | logging.warning("*****************") 258 | 259 | ``` 260 | #### 五、执行包(run.py) 261 | ```python 262 | import util.common as common 263 | import sys 264 | 265 | # FILENAME = sys.argv[1] 266 | 267 | FILENAME = "proUser.ini" 268 | 269 | """1.新建测试报告目录""" 270 | common.reset_report(filename=FILENAME) 271 | 272 | """2.执行测试用例""" 273 | common.run_test(filename=FILENAME) 274 | 275 | ``` 276 | > ###### PS:有个全局变量包constant.py,里面看到是参数目录文件相关的。 277 | --------------------------------------------------------------------------------