├── .gitattributes ├── .idea ├── autotest(1).iml ├── autotest.iml ├── encodings.xml ├── misc(1).xml ├── misc.xml ├── modules(1).xml ├── modules.xml ├── vcs.xml ├── workspace(1).xml └── workspace.xml ├── .project ├── .pydevproject ├── README.md ├── apitest ├── HTMLTestRunner.py ├── __init__.py ├── __pycache__ │ ├── HTMLTestRunner.cpython-37.pyc │ ├── __init__.cpython-36.pyc │ ├── __init__.cpython-37.pyc │ ├── admin.cpython-36.pyc │ ├── admin.cpython-37.pyc │ ├── apistep_case.cpython-37.pyc │ ├── apistest_case.cpython-37.pyc │ ├── models.cpython-36.pyc │ ├── models.cpython-37.pyc │ ├── views.cpython-36.pyc │ └── views.cpython-37.pyc ├── admin.py ├── apistep_case.py ├── apistest_case.py ├── apps.py ├── apptasks.py ├── autotest_case3.py ├── autotest_case4.py ├── celery.py ├── geckodriver.exe ├── gson-1.6.jar ├── migrations │ ├── 0001_initial.py │ ├── 0002_auto_20181226_2300.py │ ├── 0003_apis.py │ ├── __init__.py │ └── __pycache__ │ │ ├── 0001_initial.cpython-36.pyc │ │ ├── 0001_initial.cpython-37.pyc │ │ ├── 0002_auto_20181226_2300.cpython-36.pyc │ │ ├── 0002_auto_20181226_2300.cpython-37.pyc │ │ ├── 0003_apis.cpython-36.pyc │ │ ├── 0003_apis.cpython-37.pyc │ │ ├── __init__.cpython-36.pyc │ │ └── __init__.cpython-37.pyc ├── models.py ├── runtest.py ├── tasks.py ├── templates │ ├── apis_manage.html │ ├── apis_report.html │ ├── apistep_manage.html │ ├── apitest_manage.html │ ├── apitest_report.html │ ├── home.html │ ├── left.html │ ├── login.html │ ├── periodic_task.html │ ├── report.html │ └── welcome.html ├── testTaskId.py ├── tests.py └── views.py ├── apptest ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-37.pyc │ ├── admin.cpython-37.pyc │ ├── appviews.cpython-37.pyc │ └── models.cpython-37.pyc ├── admin.py ├── apps.py ├── appviews.py ├── migrations │ ├── 0001_initial.py │ ├── __init__.py │ └── __pycache__ │ │ ├── 0001_initial.cpython-37.pyc │ │ └── __init__.cpython-37.pyc ├── models.py ├── templates │ ├── appcase_manage.html │ ├── appcasestep_manage.html │ └── apptest_report.html └── tests.py ├── autotest ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-36.pyc │ ├── __init__.cpython-37.pyc │ ├── settings.cpython-36.pyc │ ├── settings.cpython-37.pyc │ ├── urls.cpython-36.pyc │ ├── urls.cpython-37.pyc │ ├── wsgi.cpython-36.pyc │ └── wsgi.cpython-37.pyc ├── settings.py ├── urls.py └── wsgi.py ├── bug ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-37.pyc │ ├── admin.cpython-37.pyc │ ├── bugviews.cpython-37.pyc │ └── models.cpython-37.pyc ├── admin.py ├── apps.py ├── bugviews.py ├── migrations │ ├── 0001_initial.py │ ├── __init__.py │ └── __pycache__ │ │ ├── 0001_initial.cpython-37.pyc │ │ └── __init__.cpython-37.pyc ├── models.py ├── templates │ └── bug_manage.html └── tests.py ├── db(1).sqlite3 ├── db.sqlite3 ├── manage.py ├── product ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-36.pyc │ ├── __init__.cpython-37.pyc │ ├── admin.cpython-36.pyc │ ├── admin.cpython-37.pyc │ ├── models.cpython-36.pyc │ ├── models.cpython-37.pyc │ ├── proviews.cpython-36.pyc │ └── proviews.cpython-37.pyc ├── admin.py ├── apps.py ├── migrations │ ├── 0001_initial.py │ ├── __init__.py │ └── __pycache__ │ │ ├── 0001_initial.cpython-36.pyc │ │ ├── 0001_initial.cpython-37.pyc │ │ ├── __init__.cpython-36.pyc │ │ └── __init__.cpython-37.pyc ├── models.py ├── proviews.py ├── templates │ └── product_manage.html └── tests.py ├── project ├── pydevproject ├── set ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-37.pyc │ ├── admin.cpython-37.pyc │ ├── models.cpython-37.pyc │ └── setviews.cpython-37.pyc ├── admin.py ├── apps.py ├── migrations │ ├── 0001_initial.py │ ├── __init__.py │ └── __pycache__ │ │ ├── 0001_initial.cpython-37.pyc │ │ └── __init__.cpython-37.pyc ├── models.py ├── setviews.py ├── templates │ ├── set_manage.html │ └── set_user.html └── tests.py ├── static ├── css │ └── bootstrap.min.css ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 └── js │ ├── bootstrap.min.js │ └── jquery.min.js └── webtest ├── __init__.py ├── __pycache__ ├── __init__.cpython-37.pyc ├── admin.cpython-37.pyc ├── models.cpython-37.pyc └── webviews.cpython-37.pyc ├── admin.py ├── apps.py ├── migrations ├── 0001_initial.py ├── __init__.py └── __pycache__ │ ├── 0001_initial.cpython-37.pyc │ └── __init__.cpython-37.pyc ├── models.py ├── templates ├── webcase_manage.html ├── webcasestep_manage.html └── webtest_report.html ├── tests.py └── webviews.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.idea/autotest(1).iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | -------------------------------------------------------------------------------- /.idea/autotest.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/misc(1).xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | -------------------------------------------------------------------------------- /.idea/modules(1).xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | autotest 4 | 5 | 6 | 7 | 8 | 9 | org.python.pydev.PyDevBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.python.pydev.pythonNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.pydevproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | Default 4 | python 2.7 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 接口自动化测试平台 2 | 3 | ##### 一. 开发方案 (后续可以集成app 和 web 自动化) 4 | 5 | ![img](https://upload-images.jianshu.io/upload_images/1663823-ca3f70cd910f321e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 6 | 7 | ##### 二. 前端展示 8 | 9 | ![img](https://upload-images.jianshu.io/upload_images/1663823-c93595ff3c4163b1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 10 | 11 | ##### 三. 单一流程接口录入和通过情况 12 | 13 | ![img](https://upload-images.jianshu.io/upload_images/1663823-88dfb2f711fe083e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 14 | 15 | ##### 四. 流程接口录入和通过情况 16 | 17 | ![img](https://upload-images.jianshu.io/upload_images/1663823-078213afe68ff73d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 18 | 19 | ![img](https://upload-images.jianshu.io/upload_images/1663823-7005c624238d0d44.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 20 | 21 | ##### 五. Bug 页面统计 以及HTMLTestRunner 生成的unittest用例执行情况报告 22 | 23 | ![img](https://upload-images.jianshu.io/upload_images/1663823-bef89badef72e1c2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 24 | 25 | ![img](https://upload-images.jianshu.io/upload_images/1663823-dacd70e1694df81c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 26 | 27 | 28 | 29 | ##### 六. 构建Jenkins 持续集成, 定时/触发执行测试用例, 以及测试结果自动邮件通知等 30 | 31 | ![img](https://upload-images.jianshu.io/upload_images/1663823-9b472fbe2ebed0fa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -------------------------------------------------------------------------------- /apitest/__init__.py: -------------------------------------------------------------------------------- 1 | import pymysql 2 | pymysql.install_as_MySQLdb() -------------------------------------------------------------------------------- /apitest/__pycache__/HTMLTestRunner.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/__pycache__/HTMLTestRunner.cpython-37.pyc -------------------------------------------------------------------------------- /apitest/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /apitest/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /apitest/__pycache__/admin.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/__pycache__/admin.cpython-36.pyc -------------------------------------------------------------------------------- /apitest/__pycache__/admin.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/__pycache__/admin.cpython-37.pyc -------------------------------------------------------------------------------- /apitest/__pycache__/apistep_case.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/__pycache__/apistep_case.cpython-37.pyc -------------------------------------------------------------------------------- /apitest/__pycache__/apistest_case.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/__pycache__/apistest_case.cpython-37.pyc -------------------------------------------------------------------------------- /apitest/__pycache__/models.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/__pycache__/models.cpython-36.pyc -------------------------------------------------------------------------------- /apitest/__pycache__/models.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/__pycache__/models.cpython-37.pyc -------------------------------------------------------------------------------- /apitest/__pycache__/views.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/__pycache__/views.cpython-36.pyc -------------------------------------------------------------------------------- /apitest/__pycache__/views.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/__pycache__/views.cpython-37.pyc -------------------------------------------------------------------------------- /apitest/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from apitest.models import Apitest, Apistep,Apis 3 | from product.models import Product 4 | # Register your models here. 5 | class ApistepAdmin(admin.TabularInline): 6 | list_display = ['apiname', 'apiurl','apiparamvalue','apimethod','apiresult','apistatus','create_time','id','apitest'] 7 | model = Apistep 8 | extra = 1 9 | 10 | class ApitestAdmin(admin.ModelAdmin): 11 | list_display = ['apitestname','apitester','apitestresult','create_time','id'] 12 | inlines = [ApistepAdmin] 13 | 14 | 15 | class ApisAdmin(admin.TabularInline): 16 | list_display = ['apiname','apiurl','apiparamvalue','apimethod','apiresult','apistatus','create_time','id','product'] 17 | 18 | admin.site.register(Apitest, ApitestAdmin) 19 | admin.site.register(Apis) 20 | 21 | 22 | 23 | # admin.site.register(ApisAdmin) 24 | 25 | #admin.site.register([Apitest, ApistepAdmin]) -------------------------------------------------------------------------------- /apitest/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ApitestConfig(AppConfig): 5 | name = 'apitest' 6 | -------------------------------------------------------------------------------- /apitest/apptasks.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | import requests,time,sys,re 4 | import urllib,zlib 5 | import pymysql 6 | 7 | import unittest 8 | from trace import CoverageResults #跟踪或跟踪Python语句执行 9 | import json 10 | from idlelib.rpc import response_queue # 11 | from apitest.celery import app 12 | 13 | from time import sleep 14 | 15 | import os 16 | from appium import webdriver 17 | 18 | PATH = lambda p:os.path.abspath(os.path.join(os.path.dirname(__file__), p)) 19 | 20 | global driver 21 | 22 | # 在appium server 与手机端建立会话关系时,手机端需要告诉服务端设备相关的一些参数, 23 | # 根据这些参数服务端可以做出相应的处理。 24 | @app.task 25 | def appauto_testcase(self): #app例 26 | desired_caps = {} 27 | # 设备系统 28 | desired_caps['platformName'] = 'Android' 29 | # 设备系统版本号 30 | desired_caps['platformVersion'] = '19' 31 | # 设备名称,必须有! 32 | desired_caps['deviceName'] = 'Android Emulator' 33 | # desired_caps['app'] = r'D:\test\test.apk' #被测试的APP在电脑的路径 34 | # 应用的包名,在参数中如果添加了应用的安装路径,就可以不用写包名和启动的activity参数 35 | desired_caps['appPackage'] = 'com.android.calculator2' 36 | desired_caps['appActivity'] = '.Calculator' 37 | time.sleep(1) 38 | self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps) 39 | time.sleep(1) 40 | sql = "SELECT id,appfindmethod, appevelement, appoptmethod,appassertdata,`apptestresult` from apptest_appcasestep where apptest_appcasestep.Appcase_id=1 ORDER BY id ASC " 41 | coon = pymysql.connect(user='root',passwd='test123456',db='autotest',port=3306,host='127.0.0.1',charset='utf8') 42 | cursor = coon.cursor() 43 | aa = cursor.execute(sql) 44 | info = cursor.fetchmany(aa) 45 | for ii in info: 46 | case_list = [] 47 | case_list.append(ii) 48 | apptestcase(self,case_list) 49 | coon.commit() 50 | cursor.close() 51 | coon.close() 52 | self.driver.quit() 53 | 54 | 55 | 56 | def apptestcase(self,case_list): 57 | for case in case_list: 58 | try: 59 | case_id = case[0] 60 | findmethod = case[1] 61 | evelement = case[2] 62 | optmethod = case[3] 63 | except Exception as e: 64 | return '测试用例格式不正确!%s'%e 65 | print(evelement) 66 | time.sleep(10) 67 | if optmethod== 'click' and findmethod=='find_element_by_id': 68 | self.driver.find_element_by_id(evelement).send_keys('test') 69 | elif optmethod== 'click' and findmethod=='find_element_by_name': 70 | self.driver.find_element_by_name(evelement).click() 71 | elif optmethod=='sendkey': 72 | self.driver.find_element_by_name(evelement).send_keys() 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /apitest/autotest_case3.py: -------------------------------------------------------------------------------- 1 | import requests,time,re,sys 2 | import urllib,zlib 3 | import pymysql 4 | import HTMLTestRunner 5 | import unittest 6 | from trace import CoverageResults 7 | import json 8 | from idlelib.rpc import response_queue 9 | from time import sleep 10 | 11 | HOSTNAME = '127.0.0.1' 12 | 13 | class ApiTest(unittest.TestCase): 14 | #读取数据库中的单一流程接口测试用例,这个可以从页面添加 15 | def test_readApiscase(self): 16 | sql = "SELECT id,apiname,apiurl,apimethod,apiparamvalue,apiresult,apistatus from apitest_apis " 17 | coon = pymysql.connect(user='root',passwd='123456',db='autotest',port=3306,host='127.0.0.1',charset='utf8') 18 | cursor = coon.cursor() 19 | aa = cursor.execute(sql) 20 | info = cursor.fetchmany(aa) 21 | print(info)#这里返回元组() ((2, '百度搜索', 'https://www.baidu.com/', 'get', 's?wd=谷歌', '谷歌', 0),) 22 | for ii in info: 23 | case_list = [] 24 | case_list.append(ii) 25 | print(case_list)#这里返回列表[] [(2, '百度搜索', 'https://www.baidu.com/', 'get', 's?wd=谷歌', '谷歌', 0)] 26 | interfaceTest(case_list) 27 | coon.commit() 28 | cursor.close() 29 | coon.close() 30 | 31 | #读取测试用例,并执行,判断结果,记录结果,有bug记录进bug管理系统 32 | def interfaceTest(case_list): 33 | res_flags = [] 34 | request_urls = [] 35 | responses = [] 36 | strinfo = re.compile('{seturl}') #正则表达式 37 | for case in case_list: 38 | try: 39 | case_id = case[0] 40 | interface_name = case[1] 41 | print(interface_name) #百度搜索 42 | url = case[2] 43 | method = case[3] 44 | param = case[4] 45 | print(param) #s?wd=谷歌 46 | res_check = case[5] 47 | print(res_check) 48 | except Exception as e: 49 | return '测试用例格式不对 %s' %e 50 | if param=='': 51 | # 如果请求参数是空的话,请求报文就是url,然后把请求报文存到请求报文list中 52 | 53 | #new_url = 'http://'+'api.test.com.cn'+url 54 | new_url = url 55 | request_urls.append(new_url) 56 | 57 | elif param=='null': 58 | url = strinfo.sub(str(seturl('seturl')),url) 59 | new_url = 'http://' +url 60 | 61 | elif '{' in param: 62 | new_url = url 63 | request_urls.append(new_url) 64 | else: 65 | 66 | url = strinfo.sub(str(seturl('seturl')), url) 67 | print(url) 68 | new_url = url + '?' + urlParam(param) # 请求报文 69 | print(new_url) 70 | request_urls.append(new_url) 71 | 72 | if method.upper() == 'GET': 73 | print(new_url) 74 | headers = { 75 | 'Authorization':'', 76 | 'Content-Type':'application/json', 77 | } 78 | if "=" in urlParam(param): 79 | data = None 80 | # print(str(case_id)+' request is get' + str(new_url.encode('utf-8'))+ '?' +str(urlParam(param).encode('utf-8'))) 81 | 82 | results = requests.get(new_url).text 83 | print('response is get' + results) 84 | responses.append(results) 85 | res = readRes(results, res_check) 86 | 87 | else: 88 | print('request is get '+ new_url+'body is'+ urlParam(param)) 89 | data = urlParam(param) 90 | req = urllib.request.Request(url=new_url,data=data,headers=headers,method="GET") 91 | try: 92 | results = urllib.request.urlopen(req).read() 93 | print('response is get') 94 | print(results) 95 | except Exception as e: 96 | return caseWriteResult(case_id,'0') 97 | res = readRes(results,res_check) 98 | if 'pass' == res: 99 | res_flags.append('pass') 100 | writeResult(case_id,'1') 101 | caseWriteResult(case_id,'1') 102 | else: 103 | res_flags.append('fail') 104 | writeResult(case_id,'0') 105 | caseWriteResult(case_id,'0') 106 | writeBug(case_id,interface_name,new_url,results,res_check) 107 | 108 | 109 | if method.upper()=="POST": 110 | headers={ 111 | # 'Authorization': 'Credential' + id, 112 | 'Content-Type': 'application/json' 113 | } 114 | if "=" in urlParam(param): 115 | data = None 116 | results = requests.patch(new_url + '?' +urlParam(param),data,headers=headers).text 117 | print('response is post' + results.encode('utf-8')) 118 | responses.append(results) 119 | res = readRes(results, '') 120 | else: 121 | print(str(case_id)+' request is '+ url + ' body is ' + str(urlParam(param))) 122 | #form = json.dumps(param) 123 | results = requests.post(new_url,data=param,headers=headers).text 124 | print('response is post'+ str(results)) 125 | responses.append(results) 126 | res = readRes(results,res_check) 127 | if 'pass' == res: 128 | writeResult(case_id, '1') 129 | res_flags.append('pass') 130 | caseWriteResult(case_id, '1') 131 | else: 132 | writeResult(case_id, '0') 133 | res_flags.append('fail') 134 | caseWriteResult(case_id, '0') 135 | writeBug(case_id, interface_name, new_url, results, res_check) 136 | 137 | 138 | def readRes(res, res_check): 139 | res = str(res.replace('":"',"=").replace('":',"=")) 140 | print(res) 141 | res_check = res_check.split(':') 142 | print(res_check) 143 | for s in res_check: 144 | if s in res: 145 | pass 146 | else: 147 | return '错误,返回参数和预期结果不一致'+s 148 | return 'pass' 149 | 150 | def urlParam(param): 151 | param1 = param.replace('"','"') 152 | return param1 153 | 154 | def CredentialId(): 155 | global id 156 | url = 'http://' + 'api.test.com.cn'+'/api/Security/Authentication/Signin/web' 157 | body_data = json.dumps({"Identity":'test',"Password":'test'}) 158 | headers = { 159 | 'Connection':'keep-alive', 160 | 'Content-Type':'application/json' 161 | } 162 | response = requests.post(url=url,data=body_data,headers=headers) 163 | data = response.text 164 | regx = '.*"CredentialId":"(.*)","Scene"' 165 | pm = re.search(regx,data) 166 | id = pm.group(1) 167 | 168 | def seturl(set): 169 | global setvalue 170 | sql = "SELECT setname,setvalue from set_set" 171 | coon = pymysql.connect(user='root',passwd='123456',db='autotest',port=3306,host=HOSTNAME,charset='utf8') 172 | cursor = coon.cursor() 173 | aa = cursor.execute(sql) 174 | info = cursor.fetchmany(aa) 175 | print('info is ') 176 | print(info) #(('testurl', '127.0.0.1'),) 177 | coon.commit() 178 | cursor.close() 179 | coon.close() 180 | if info[0][0] == set: 181 | setvalue = info[0][1] 182 | print('setvalue is '+ setvalue) 183 | return setvalue 184 | 185 | #流程接口的结果写入 186 | def writeResult(case_id,result): 187 | result = result.encode('utf-8') 188 | now = time.strftime("%Y-%m-%d %H:%M:%S") 189 | print(now) 190 | param = (result, now, case_id) 191 | sql = "UPDATE apitest_apis set `apistatus`=%s, `create_time`=%s WHERE `id`=%s;"#, (str(result), str(now), str(case_id)) 192 | print('api autotest result is '+ result.decode()) 193 | coon = pymysql.connect(user='root', passwd='123456', db='autotest', port=3306, host=HOSTNAME, charset='utf8') 194 | cursor = coon.cursor() 195 | cursor.execute(sql,param) 196 | coon.commit() 197 | cursor.close() 198 | coon.close() 199 | 200 | def caseWriteResult(case_id,result): 201 | result = result.encode('utf-8') 202 | print(str(result)) 203 | now = time.strftime("%Y-%m-%d %H:%M:%S") 204 | sql = "UPDATE apitest_apitest set apitest_apitest.apitestresult=%s, apitest_apitest.create_time=%s where apitest_apitest.id=%s;" 205 | param = (result, now, case_id) 206 | print('api autotest result is ' + result.decode()) 207 | coon = pymysql.connect(user='root', passwd='123456', db='autotest', port=3306, host='127.0.0.1', charset='utf8') 208 | cursor = coon.cursor() 209 | cursor.execute(sql, param) 210 | coon.commit() 211 | cursor.close() 212 | coon.close() 213 | 214 | #bug记录进bug管理表 215 | def writeBug(bug_id,interface_name,request,response,res_check): 216 | interface_name = interface_name.encode('utf-8') 217 | #res_check = res_check.encode('utf-8') 218 | request = request.encode('utf-8') 219 | now = time.strftime("%Y-%m-%d %H:%M:%S") 220 | bugname = str(bug_id) + '_' + interface_name.decode() + '_出错了' 221 | bugdetail = '[请求数据]
' + str(request) + '
' + '[预期结果]
' + str(res_check) + '
' + '
' + '[响应数据]
' + '
' + str(response) 222 | print(bugdetail) 223 | sql = "INSERT INTO `bug_bug` (" \ 224 | "`bugname`,`bugdetail`,`bugstatus`,`buglevel`, `bugcreater`, `bugassign`,`created_time`,`Product_id`) " \ 225 | "VALUES ('%s','%s','激活','3','kxy', 'kxy', '%s', '2');" % (bugname, pymysql.escape_string(bugdetail), now) 226 | coon = pymysql.connect(user='root', passwd='123456', db='autotest', port=3306, host='127.0.0.1', charset='utf8') 227 | cursor = coon.cursor() 228 | cursor.execute(sql) 229 | coon.commit() 230 | cursor.close() 231 | coon.close() 232 | 233 | if __name__ == '__main__': 234 | 235 | test_readSQLcase() 236 | print('Done') 237 | time.sleep(1) 238 | 239 | 240 | 241 | 242 | -------------------------------------------------------------------------------- /apitest/celery.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | import os 3 | import django 4 | from celery import Celery #一个简单、灵活和可靠的分布式任务处理系统。专注实时任务队列,也支持任务调度。 5 | from django.conf import settings 6 | 7 | # set the default Django settings module for the 'celery' program. 8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'autotest.settings') 9 | django.setup() 10 | 11 | app = Celery('autotest') 12 | 13 | # Using a string here means the worker will not have to 14 | # pickle the object when using Windows. 15 | app.config_from_object('django.conf:settings') 16 | app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) 17 | -------------------------------------------------------------------------------- /apitest/geckodriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/geckodriver.exe -------------------------------------------------------------------------------- /apitest/gson-1.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/gson-1.6.jar -------------------------------------------------------------------------------- /apitest/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0.2 on 2018-12-26 14:53 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ('product', '0001_initial'), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='Apistep', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('apiname', models.CharField(max_length=100, verbose_name='接口名称')), 21 | ('apiurl', models.CharField(max_length=200, verbose_name='url地址')), 22 | ('apiparamvalue', models.CharField(max_length=800, verbose_name='请求参数和值')), 23 | ('apimethod', models.CharField(choices=[('get', 'get'), ('post', 'post'), ('put', 'put'), ('delete', 'delete'), ('patch', 'patch')], default='get', max_length=200, null=True, verbose_name='请求方法')), 24 | ('apiresult', models.CharField(max_length=200, verbose_name='预期结果')), 25 | ('apistatus', models.BooleanField(verbose_name='是否通过')), 26 | ('create_time', models.DateTimeField(auto_now=True, verbose_name='创建时间')), 27 | ], 28 | ), 29 | migrations.CreateModel( 30 | name='Apitest', 31 | fields=[ 32 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 33 | ('apitestname', models.CharField(max_length=64, verbose_name='流程接口名称')), 34 | ('apitestdesc', models.CharField(max_length=64, null=True, verbose_name='描述')), 35 | ('apitester', models.CharField(max_length=16, verbose_name='测试负责人')), 36 | ('apitestresult', models.BooleanField(verbose_name='测试结果')), 37 | ('create_time', models.DateTimeField(auto_now=True, verbose_name='创建时间')), 38 | ('Product', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='product.Product')), 39 | ], 40 | options={ 41 | 'verbose_name': '流程场景接口', 42 | 'verbose_name_plural': '流程场景接口', 43 | }, 44 | ), 45 | migrations.AddField( 46 | model_name='apistep', 47 | name='Apitest', 48 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='apitest.Apitest'), 49 | ), 50 | ] 51 | -------------------------------------------------------------------------------- /apitest/migrations/0002_auto_20181226_2300.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0.2 on 2018-12-26 15:00 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('apitest', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='apistep', 15 | name='apiresponse', 16 | field=models.CharField(max_length=5000, null=True, verbose_name='响应数据'), 17 | ), 18 | migrations.AddField( 19 | model_name='apistep', 20 | name='apistep', 21 | field=models.CharField(max_length=100, null=True, verbose_name='测试步聚'), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /apitest/migrations/0003_apis.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0.2 on 2018-12-27 00:45 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('product', '0001_initial'), 11 | ('apitest', '0002_auto_20181226_2300'), 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Apis', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('apiname', models.CharField(max_length=100, verbose_name='接口名称')), 20 | ('apiurl', models.CharField(max_length=200, verbose_name='url地址')), 21 | ('apiparamvalue', models.CharField(max_length=800, verbose_name='请求参数和值')), 22 | ('apimethod', models.CharField(choices=[('get', 'get'), ('post', 'post'), ('put', 'put'), ('delete', 'delete'), ('patch', 'patch')], default='get', max_length=200, null=True, verbose_name='请求方法')), 23 | ('apitester', models.CharField(max_length=16, null=True, verbose_name='测试负责人')), 24 | ('apiresult', models.CharField(max_length=200, verbose_name='预期结果')), 25 | ('apiresponse', models.CharField(max_length=5000, null=True, verbose_name='响应数据')), 26 | ('apistatus', models.BooleanField(verbose_name='是否通过')), 27 | ('create_time', models.DateTimeField(auto_now=True, verbose_name='创建时间')), 28 | ('Product', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='product.Product')), 29 | ], 30 | options={ 31 | 'verbose_name': '单一场景接口', 32 | 'verbose_name_plural': '单一场景接口', 33 | }, 34 | ), 35 | ] 36 | -------------------------------------------------------------------------------- /apitest/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/migrations/__init__.py -------------------------------------------------------------------------------- /apitest/migrations/__pycache__/0001_initial.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/migrations/__pycache__/0001_initial.cpython-36.pyc -------------------------------------------------------------------------------- /apitest/migrations/__pycache__/0001_initial.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/migrations/__pycache__/0001_initial.cpython-37.pyc -------------------------------------------------------------------------------- /apitest/migrations/__pycache__/0002_auto_20181226_2300.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/migrations/__pycache__/0002_auto_20181226_2300.cpython-36.pyc -------------------------------------------------------------------------------- /apitest/migrations/__pycache__/0002_auto_20181226_2300.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/migrations/__pycache__/0002_auto_20181226_2300.cpython-37.pyc -------------------------------------------------------------------------------- /apitest/migrations/__pycache__/0003_apis.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/migrations/__pycache__/0003_apis.cpython-36.pyc -------------------------------------------------------------------------------- /apitest/migrations/__pycache__/0003_apis.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/migrations/__pycache__/0003_apis.cpython-37.pyc -------------------------------------------------------------------------------- /apitest/migrations/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/migrations/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /apitest/migrations/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kangxianying/autotest/65904ad7aa2590aac35a7c7abcd2c07b2d7f0938/apitest/migrations/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /apitest/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from product.models import Product 3 | 4 | # Create your models here. 5 | class Apitest(models.Model): 6 | Product = models.ForeignKey('product.Product', on_delete=models.CASCADE, null=True) 7 | apitestname = models.CharField('流程接口名称', max_length=64) #流程接口测试场景 8 | apitestdesc = models.CharField('描述',max_length=64, null=True) #流程接口描述 9 | apitester = models.CharField('测试负责人',max_length=16) #执行人 10 | apitestresult = models.BooleanField('测试结果') #流程接口测试结果 11 | create_time = models.DateTimeField('创建时间', auto_now=True) #创建时间,自动获取当前时间 12 | 13 | class Meta: 14 | verbose_name = '流程场景接口' 15 | verbose_name_plural = '流程场景接口' 16 | def __str__(self): 17 | return self.apitestname 18 | 19 | 20 | class Apistep(models.Model): 21 | Apitest = models.ForeignKey('Apitest',on_delete=models.CASCADE) #关联接口ID 22 | apistep = models.CharField('测试步聚', max_length=100, null=True) # 测试步聚 23 | 24 | apiname = models.CharField('接口名称',max_length=100) #接口标题 25 | apiurl = models.CharField('url地址',max_length=200) #地址 26 | REQUEST_METHOD = (('get','get'),('post','post'),('put','put'),('delete','delete'),('patch','patch')) 27 | apiparamvalue = models.CharField('请求参数和值',max_length=800) #请求参数和值 28 | apimethod = models.CharField(verbose_name='请求方法', choices=REQUEST_METHOD,default='get',max_length=200,null=True) #请求方法 29 | apiresult = models.CharField('预期结果', max_length=200)#预期结果 30 | apiresponse = models.CharField('响应数据', max_length=5000, null=True) # 响应数据 31 | 32 | apistatus = models.BooleanField('是否通过') 33 | create_time = models.DateTimeField('创建时间', auto_now=True) #创建时间,自动获取当前时间 34 | def __str__(self): 35 | return self.apistep 36 | 37 | 38 | 39 | class Apis(models.Model): 40 | Product = models.ForeignKey('product.Product', on_delete=models.CASCADE, null=True) # 关联产品id 41 | apiname = models.CharField('接口名称', max_length=100) # 接口标题 42 | apiurl = models.CharField('url地址', max_length=200) # 地址 43 | apiparamvalue = models.CharField('请求参数和值', max_length=800) # 请求参数和值 44 | REQUEST_METHOD = (('get', 'get'), ('post', 'post'), ('put', 'put'), ('delete', 'delete'), ('patch', 'patch')) 45 | apimethod = models.CharField(verbose_name='请求方法', choices=REQUEST_METHOD, default='get', max_length=200, 46 | null=True) # 请求方法 47 | apitester = models.CharField('测试负责人', max_length=16, null=True) # 执行人 48 | apiresult = models.CharField('预期结果', max_length=200) # 预期结果 49 | apiresponse = models.CharField('响应数据', max_length=5000, null=True) # 响应数据 50 | apistatus = models.BooleanField('是否通过') # 测试结果 51 | create_time = models.DateTimeField('创建时间', auto_now=True) # 创建时间-自动获取当前时间 52 | 53 | class Meta: 54 | verbose_name = '单一场景接口' 55 | verbose_name_plural = '单一场景接口' 56 | 57 | def __str__(self): 58 | return self.apiname 59 | 60 | -------------------------------------------------------------------------------- /apitest/runtest.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import json 3 | import requests 4 | import HTMLTestRunner 5 | import time 6 | 7 | from apistest_case import ApisTest 8 | from apistep_case import ApistepTest 9 | 10 | if __name__ == '__main__': 11 | now = time.strftime("%Y-%m-%d-%H_%M_%S", time.localtime(time.time())) 12 | testunit = unittest.TestSuite() 13 | testunit.addTest(ApisTest("test_readApiscase")) 14 | testunit.addTest(ApistepTest("test_readApistepcase")) 15 | filename = "G:\\autotest\\apitest\\templates\\report.html" 16 | fp = open(filename, 'wb') 17 | runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title=u"全部接口测试报告", description=u"全部接口") 18 | runner.run(testunit) 19 | 20 | print('Done!') 21 | time.sleep(1) -------------------------------------------------------------------------------- /apitest/tasks.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | import requests, time, sys, re 4 | import urllib, zlib 5 | import pymysql 6 | 7 | import unittest 8 | from trace import CoverageResults #查看代码覆盖率 9 | 10 | import json 11 | from idlelib.rpc import response_queue #队列,线程间最常用的交换数据的形式 12 | from apitest.celery import app 13 | 14 | from time import sleep 15 | 16 | import os 17 | from selenium import webdriver 18 | #from appium import webdriver 19 | 20 | 21 | PATH = lambda p:os.path.abspath(os.path.join(os.path.dirname(__file__),p)) 22 | global driver 23 | 24 | @app.task 25 | def hello_world(): 26 | print('已运行') 27 | 28 | @app.task(bind=True) 29 | def debug_task(self): 30 | print('Request: {0!r}'.format(self.request)) 31 | 32 | @app.task 33 | def apisauto_testcase(): 34 | sql = "SELECT id,apiname,apiurl,apimethod,apiparamvalue,apiresult,apistatus from apitest_apis " 35 | coon = pymysql.connect(user='root', passwd='test123456', db='autotest', port=3306, host='127.0.0.1', charset='utf8') 36 | cursor = coon.cursor() 37 | aa = cursor.execute(sql) 38 | info = cursor.fetchmany(aa) 39 | print(info) 40 | for ii in info: 41 | case_list = [] 42 | case_list.append(ii) 43 | interfaceTest1(case_list) 44 | coon.commit() 45 | cursor.close() 46 | coon.close() 47 | 48 | def interfaceTest1(case_list): 49 | res_flags = [] 50 | request_urls = [] 51 | responses = [] 52 | strinfo = re.compile('{seturl}') 53 | for case in case_list: 54 | try: 55 | case_id = case[0] 56 | interface_name = case[1] 57 | url = case[2] 58 | method = case[3] 59 | param = case[4] 60 | res_check = case[5] 61 | except Exception as e: 62 | return '测试用例格式不正确!%s'%e 63 | if param == '': 64 | new_url = 'http://' +url 65 | elif param == 'null': 66 | url = strinfo.sub(str(seturl('seturl')),url) 67 | new_url = 'http://' +url 68 | else: 69 | url = strinfo.sub(str(seturl('seturl')), url) 70 | new_url = 'http://' + url 71 | request_urls.append(new_url) 72 | if method.upper() =='GET': 73 | headers = {'Authorization':'', 'Content-Type':'application/json'} 74 | if "=" in urlParam(param): 75 | data = None 76 | print(str(case_id)+ 'request is get' + new_url.encode('utf-8') + '?' + urlParam(param).encode('utf-8')) 77 | 78 | 79 | 80 | 81 | def seturl(set): 82 | global setvalue 83 | sql = "SELECT `setname`,`setvalue` from set_set" 84 | coon = pymysql.connect(user='root',passwd='test123456',db='autotest',port=3306,host='127.0.0.1',charset='utf8') 85 | cursor = coon.cursor() 86 | aa = cursor.execute(sql) 87 | info = cursor.fetchmany(aa) 88 | print(info) 89 | coon.commit() 90 | cursor.close() 91 | coon.close() 92 | if info[0][0] ==set: 93 | setvalue = info[0][1] 94 | print(setvalue) 95 | return setvalue 96 | 97 | def urlParam(param): 98 | paraml = param.replace('"','"') 99 | return paraml 100 | 101 | -------------------------------------------------------------------------------- /apitest/templates/apis_manage.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | {% load bootstrap4 %} 5 | {% bootstrap_css %} 6 | {% bootstrap_javascript %} 7 | 产品自动化测试管理平台 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 60 | 61 |