日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

搭建接口自动化测试框架详细过程

發(fā)布時間:2023/12/10 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 搭建接口自动化测试框架详细过程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?搭建接口自動化測試框架(文中接口數據來自于光榮之路)

在設計接口測試框架前,先來弄清楚接口測試怎么進行的,請求和響應都是什么樣的,清楚這些之后再進行下一步的操作。

步驟1:新建工程interfaceFramework_practice1,在工程下新建包testScripts用于存放測試腳本文件,在該包下新建testScript.py用戶寫請求代碼

?

按照接口文檔的描述,下面的接口實現了用戶的注冊、登錄、寫博客、修改、刪除博客等功能,先把每一個接口用代碼實現一下。
接口說明:

接口返回code說明:

'00'?:?成功

'01':用戶已存在

'02':參數不合法

'03':參數錯誤(1、用戶信息錯誤?2、參數錯誤,數據庫中不存在相應數據)

'999':未知錯誤,看后臺日志

?

1、用戶注冊

?

?

參數規(guī)則說明:

username:

1、必須字母和數字組成

2、長度2~20位

3、字母不區(qū)分大小寫

?

password:

1、長度8~20位

2、必須含有字母和數字

?

email:

標準的email規(guī)則

?

請求的url: http://39.106.41.29:8080/register/

?

Json串格式參數,請求示例:

{"username": "xufengchai6", "password": "xufengchai121", "email": "xufengchai@qq.com"}

?

響應示例:

{"code": "00", "userid": 48}

?

代碼:

#encoding=utf-8

import requests

import json

import os

import hashlib

import random

num=random.randint(0,100)

print "register------"

d={"username":"xufengchai%s"%num,"password":"xufengchai121","email":"xufengchai@qq.com"}

print "data before json.dumps:",d

data = json.dumps(d) #

print "data after json.dumps:",data

r = requests.post('http://39.106.41.29:8080/register/', data= data)

print "r.status code:",r.status_code

print "r.text:",r.text

print "type(r.json()):",type(r.json())

print "str(r.json()):",str(r.json())

?

結果:

C:\Python27\python.exe D:/test/interfaceFramework_practice1/testScripts/testScript.py

register------

data before json.dumps: {'username': 'xufengchai6', 'password': 'xufengchai121', 'email': 'xufengchai@qq.com'}

data after json.dumps: {"username": "xufengchai6", "password": "xufengchai121", "email": "xufengchai@qq.com"}

r.status code: 200

r.text: {"code": "00", "userid": 48}

type(r.json()): <type 'dict'>

str(r.json()): {u'code': u'00', u'userid': 48}

?

Process finished with exit code 0

?

可以看到,請求參數包括用戶名,密碼,郵箱,返回的是code和userid,code指明注冊情況,userid用于后續(xù)處理博文的用戶標識

2、用戶登錄

?

Json串格式參數,請求示例:

{"username": "xufengchai6", "password": "7f73a2e4d8b01b0f0f1062a59d4df635"}

響應示例:

成功:

{"token": "290cbf8f1438f3d8f56d9026604de336", "code": "00", "userid": 48, "login_time": "2018-08-05 10:22:05"}

失敗:

{"code": "03", "params": {"username": "xufengchai6", "passwod": "7f73a2e4d8b01b0f0f1062a59d4df635"}}

?

代碼:

#encoding=utf-8

import requests

import json

import os

import hashlib

import random

?

md5=hashlib.md5()

md5.update('xufengchai121')

pwd=md5.hexdigest()#轉成16進制

print pwd

?

print "login------"

data=json.dumps({'username':'xufengchai6','password':pwd})

print "data:",data

r=requests.post('http://39.106.41.29:8080/login/',data=data)

?

print "r.status code:",r.status_code

print "r.text:",r.text

print "type(r.json()):",type(r.json())

print "str(r.json()):",str(r.json())

?

結果:

C:\Python27\python.exe D:/test/interfaceFramework_practice1/testScripts/testScript.py

7f73a2e4d8b01b0f0f1062a59d4df635

login------

data: {"username": "xufengchai6", "password": "7f73a2e4d8b01b0f0f1062a59d4df635"}

r.status code: 200

r.text: {"token": "290cbf8f1438f3d8f56d9026604de336", "code": "00", "userid": 48, "login_time": "2018-08-05 10:22:05"}

type(r.json()): <type 'dict'>

str(r.json()): {u'token': u'290cbf8f1438f3d8f56d9026604de336', u'code': u'00', u'userid': 48, u'login_time': u'2018-08-05 10:22:05'}

?

Process finished with exit code 0

?

如果登錄成功,會返回token,code,userid等信息

3、新增博文

Json串格式參數,請求示例:

{'userid':48,'token':'290cbf8f1438f3d8f56d9026604de336','title':'practice','content':'interface learn'}

響應示例

{"data": [{"content": "interface learn", "title": "practice"}], "code": "00", "userid": 48}

?

代碼:

#encoding=utf-8

import requests

import json

import os

import hashlib

import random

?

md5=hashlib.md5()

md5.update('xufengchai121')

pwd=md5.hexdigest()#轉成16進制

print pwd

?

print "create post------"

data=json.dumps({'userid':48,'token':'290cbf8f1438f3d8f56d9026604de336','title':'practice','content':'interface learn'})

print "data:",data

r=requests.post('http://39.106.41.29:8080/create/',data=data)

?

print "r.status code:",r.status_code

print "r.text:",r.text

print "type(r.json()):",type(r.json())

print "str(r.json()):",str(r.json())

?

結果:ok

C:\Python27\python.exe D:/test/interfaceFramework_practice1/testScripts/testScript.py

7f73a2e4d8b01b0f0f1062a59d4df635

create post------

data: {"content": "interface learn", "token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48, "title": "practice"}

r.status code: 200

r.text: {"data": [{"content": "interface learn", "title": "practice"}], "code": "00", "userid": 48}

type(r.json()): <type 'dict'>

str(r.json()): {u'userid': 48, u'code': u'00', u'data': [{u'content': u'interface learn', u'title': u'practice'}]}

?

Process finished with exit code 0

?

?

4、查詢用戶的博文

獲取指定用戶的博文(支持偏移量)

Offset與lines結合使用,表示跳過offset條取lines條數據,當不傳offset或lines時,獲取用戶全部博文。

Json串格式參數,請求示例:

{"token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48}

響應示例:

{"data": [{"update_time": null, "title": "practice", "content": "interface learn", "articleId": 2, "owner": 48, "posted_on": "2018-08-05 10:58:58"}, {"update_time": null, "title": "practice", "content": "interface learn", "articleId": 1, "owner": 48, "posted_on": "2018-08-05 10:35:33"}], "code": "00", "userid": 48}

?

代碼:

#encoding=utf-8

import requests

import json

import os

import hashlib

import random

?

md5=hashlib.md5()

md5.update('xufengchai121')

pwd=md5.hexdigest()#轉成16進制

print pwd

?

print "query post of user------"

data=json.dumps({'userid':48,'token':'290cbf8f1438f3d8f56d9026604de336'})

print "data:",data

r=requests.post('http://39.106.41.29:8080/getBlogsOfUser/',data=data)

?

print "r.status code:",r.status_code

print "r.text:",r.text

print "type(r.json()):",type(r.json())

print "str(r.json()):",str(r.json())

?

結果:ok

C:\Python27\python.exe D:/test/interfaceFramework_practice1/testScripts/testScript.py

7f73a2e4d8b01b0f0f1062a59d4df635

query post of user------

data: {"token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48}

r.status code: 200

r.text: {"data": [{"update_time": null, "title": "practice", "content": "interface learn", "articleId": 2, "owner": 48, "posted_on": "2018-08-05 10:58:58"}, {"update_time": null, "title": "practice", "content": "interface learn", "articleId": 1, "owner": 48, "posted_on": "2018-08-05 10:35:33"}], "code": "00", "userid": 48}

type(r.json()): <type 'dict'>

str(r.json()): {u'userid': 48, u'code': u'00', u'data': [{u'update_time': None, u'title': u'practice', u'content': u'interface learn', u'articleId': 2, u'owner': 48, u'posted_on': u'2018-08-05 10:58:58'}, {u'update_time': None, u'title': u'practice', u'content': u'interface learn', u'articleId': 1, u'owner': 48, u'posted_on': u'2018-08-05 10:35:33'}]}

?

Process finished with exit code 0

?

返回的多個博文內容是以一個列表中的多個字典形式存在。

?

?

?

5、修改博文

?

Json串格式參數,請求示例:

{'userid':48,'token':'290cbf8f1438f3d8f56d9026604de336',"articleId":1,"title": "xiaxiaoxu test", "content": "interface learn xia"}

響應示例:

{"articleId": 1, "update_time": "2018-08-05 11:16:05", "code": "00", "userid": 48}

?

代碼:

#encoding=utf-8

import requests

import json

import os

import hashlib

import random

?

md5=hashlib.md5()

md5.update('xufengchai121')

pwd=md5.hexdigest()#轉成16進制

print pwd

?

print "update post------"

data=json.dumps({'userid':48,'token':'290cbf8f1438f3d8f56d9026604de336',"articleId":1,"title": "xiaxiaoxu test", "content": "interface learn xia"})

print "data:",data

r=requests.put('http://39.106.41.29:8080/update/',data=data)

?

print "r.status code:",r.status_code

print "r.text:",r.text

print "type(r.json()):",type(r.json())

print "str(r.json()):",str(r.json())

?

結果:ok

C:\Python27\python.exe D:/test/interfaceFramework_practice1/testScripts/testScript.py

7f73a2e4d8b01b0f0f1062a59d4df635

update post------

data: {"content": "interface learn xia", "articleId": 1, "token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48, "title": "xiaxiaoxu test"}

r.status code: 200

r.text: {"articleId": 1, "update_time": "2018-08-05 11:16:05", "code": "00", "userid": 48}

type(r.json()): <type 'dict'>

str(r.json()): {u'userid': 48, u'update_time': u'2018-08-05 11:16:05', u'code': u'00', u'articleId': 1}

?

Process finished with exit code 0

?

更新博文后,會返回update_time,表示更新時間

?

6、查詢博文內容

請求地址示例:

http://localhost:8080/getBlogContent/

?

請求示例:

'http://39.106.41.29:8080/getBlogContent/'+str(articleId)

響應示例:

{"code": "00", "data": [{"update_time": "2018-08-05 11:16:05", "title": "xiaxiaoxu test", "content": "interface learn xia", "articleId": 1, "owner": 48, "posted_on": "2018-08-05 10:35:33"}]}

?

?

代碼:

#encoding=utf-8
import requests
import json
import os
import hashlib
import random


print "query post------"
articleId=1

r=requests.get('http://39.106.41.29:8080/getBlogContent/'+str(articleId))

print "r.status code:",r.status_code
print "r.text:",r.text
print "type(r.json()):",type(r.json())
print "str(r.json()):",str(r.json())

?

結果:ok

C:\Python27\python.exe D:/test/interfaceFramework_practice1/testScripts/testScript.py

query post------

r.status code: 200

r.text: {"code": "00", "data": [{"update_time": "2018-08-05 11:16:05", "title": "xiaxiaoxu test", "content": "interface learn xia", "articleId": 1, "owner": 48, "posted_on": "2018-08-05 10:35:33"}]}

type(r.json()): <type 'dict'>

str(r.json()): {u'code': u'00', u'data': [{u'update_time': u'2018-08-05 11:16:05', u'title': u'xiaxiaoxu test', u'content': u'interface learn xia', u'articleId': 1, u'owner': 48, u'posted_on': u'2018-08-05 10:35:33'}]}

?

Process finished with exit code 0

?

7、批量查詢博文

請求地址示例:

http://localhost:8080/getBlogsContent/articleIds=1,2,3

響應示例:

{"code": "00", "data": [{"update_time": "2018-08-05 11:16:05", "title": "xiaxiaoxu test", "content": "interface learn xia", "articleId": 1, "owner": 48, "posted_on": "2018-08-05 10:35:33"}, {"update_time": null, "title": "practice", "content": "interface learn", "articleId": 2, "owner": 48, "posted_on": "2018-08-05 10:58:58"}]}

?

代碼:

#encoding=utf-8

import requests

import json

import os

import hashlib

import random

?

print "query posts by blogId------"

?

r=requests.get('http://39.106.41.29:8080/getBlogsContent/'+str('articleIds=1,2'))

?

print "r.status code:",r.status_code

print "r.text:",r.text

print "type(r.json()):",type(r.json())

print "str(r.json()):",str(r.json())

?

結果:

C:\Python27\python.exe D:/test/interfaceFramework_practice1/testScripts/testScript.py

query posts by blogId------

r.status code: 200

r.text: {"code": "00", "data": [{"update_time": "2018-08-05 11:16:05", "title": "xiaxiaoxu test", "content": "interface learn xia", "articleId": 1, "owner": 48, "posted_on": "2018-08-05 10:35:33"}, {"update_time": null, "title": "practice", "content": "interface learn", "articleId": 2, "owner": 48, "posted_on": "2018-08-05 10:58:58"}]}

type(r.json()): <type 'dict'>

str(r.json()): {u'code': u'00', u'data': [{u'update_time': u'2018-08-05 11:16:05', u'title': u'xiaxiaoxu test', u'content': u'interface learn xia', u'articleId': 1, u'owner': 48, u'posted_on': u'2018-08-05 10:35:33'}, {u'update_time': None, u'title': u'practice', u'content': u'interface learn', u'articleId': 2, u'owner': 48, u'posted_on': u'2018-08-05 10:58:58'}]}

?

Process finished with exit code 0

?

8、刪除博文

Json串格式參數,示例:

{"userid":48, "token": "7f73a2e4d8b01b0f0f1062a59d4df635", "articleId":[2,3,4]}

響應示例:

{"articleId": [2, 3, 4], "code": "00", "userid": 48}

?

刪除之前先查下該用戶下有幾條博文,6條,articleId從1到6

?

?

代碼:

#encoding=utf-8

import requests

import json

import os

import hashlib

import random

?

md5=hashlib.md5()

md5.update('xufengchai121')

pwd=md5.hexdigest()#轉成16進制

print pwd

?

print "delete post------"

data=json.dumps({'userid':48,'token': 7f73a2e4d8b01b0f0f1062a59d4df635,"articleId":[2,3,4]})

print "data:",data

r=requests.delete('http://39.106.41.29:8080/delete/',data=data)

?

print "r.status code:",r.status_code

print "r.text:",r.text

print "type(r.json()):",type(r.json())

print "str(r.json()):",str(r.json())

?

結果:ok

服務器決絕處理刪除請求,可能是服務端針對刪除請求做了設置

C:\Python27\python.exe D:/test/interfaceFramework_practice1/testScripts/testScript.py

7f73a2e4d8b01b0f0f1062a59d4df635

delete post------

data: {"articleId": [2, 3, 4], "token": "7f73a2e4d8b01b0f0f1062a59d4df635", "userid": 48}

r.status code: 405

r.text: None

?

Process finished with exit code 0

?

請求和響應參數:

注冊請求和響應參數:

?

請求示例:

{"username": "xufengchai6", "password": "xufengchai121", "email": "xufengchai@qq.com"}

響應示例:

{"code": "00", "userid": 48}

?

登錄的請求和響應參數:

請求示例:

{"username": "xufengchai6", "password": "7f73a2e4d8b01b0f0f1062a59d4df635"}

響應示例:

{"token": "290cbf8f1438f3d8f56d9026604de336", "code": "00", "userid": 48, "login_time": "2018-08-05 10:22:05"}

?

查詢的請求和響應參數:

請求示例:

{"token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48}

響應示例:

{"data": [{"update_time": null, "title": "practice", "content": "interface learn", "articleId": 2, "owner": 48, "posted_on": "2018-08-05 10:58:58"}, {"update_time": null, "title": "practice", "content": "interface learn", "articleId": 1, "owner": 48, "posted_on": "2018-08-05 10:35:33"}], "code": "00", "userid": 48}

?

請求的方式:

注冊:

d={"username":"xufengchai%s"%num,"password":"xufengchai121","email":"xufengchai@qq.com"}

data = json.dumps(d)

r = requests.post('http://39.106.41.29:8080/register/', data= data)

?

登錄:

data=json.dumps({'username':'xufengchai6','password':pwd})

r=requests.post('http://39.106.41.29:8080/login/',data=data)

?

新增博文:

data=json.dumps({'userid':48,'token':'290cbf8f1438f3d8f56d9026604de336','title':'practice','content':'interface learn'})

r=requests.post('http://39.106.41.29:8080/create/',data=data)

?

查詢:

data=json.dumps({'userid':48,'token':'290cbf8f1438f3d8f56d9026604de336'})

r=requests.post('http://39.106.41.29:8080/getBlogsOfUser/',data=data)

?

修改:

data=json.dumps({'userid':48,'token':'290cbf8f1438f3d8f56d9026604de336',"articleId":1,"title": "xiaxiaoxu test", "content": "interface learn xia"})

r=requests.put('http://39.106.41.29:8080/update/',data=data)

?

查詢博文內容:

articleId=1

r=requests.get('http://39.106.41.29:8080/getBlogContent/'+str(articleId))

?

批量查詢博文內容:

r=requests.get('http://39.106.41.29:8080/getBlogsContent/'+str('articleIds=1,2'))

?

刪除博文:

data=json.dumps({'userid':48,'token': 7f73a2e4d8b01b0f0f1062a59d4df635,"articleId":[2,3,4]})

r=requests.delete('http://39.106.41.29:8080/delete/',data=data)

?

基于以上對接口的請求和響應的歸類,我們封裝一下http請求的方法

?

步驟2:封裝http請求方法

在工程下新建util包,用于放工具類,在該包下新建HttpClient.py,封裝http請求
HttpClient.py

#encoding=utf-8

import requests

import json

class HttpClient(object):

??? def __init__(self):

??????? pass

?

??? def __post(self,url,data=None,json=None,**kargs):

??????? response=requests.post(url=url,data=data,json=json)

??????? return response

?

??? def __get(self,url,params=None,**kargs):

??????? response=requests.get(url=url,params=params)

?

?

??? def request(self,requestMethod,requestUrl,paramsType,requestData=None,headers=None,cookies=None):

??????? if requestMethod.lower() == "post":

??????????? if paramsType == "form":

????????????? ??response=self.__post(url=requestUrl,data=json.dumps(eval(requestData)),headers=headers,cookies=cookies)

??????????????? return response

??????????? elif paramsType == 'json':

??????????????? response = self.__post(url=requestUrl,json=json.dumps(eval(requestData)),headers=headers,cookies=cookies)

??????????????? return response

??????? elif requestMethod == "get":

??????????? if paramsType == "url":

??????????????? request_url="%s%s" %(requestUrl,requestData)

??????????????? response=self.__get(url=request_url,headers=headers,cookies=cookies)

??????????????? return response

??????????? elif paramsType == "params":

??????????????? response=self.__get(url=requestUrl,params=requestData,headers=headers,cookies=cookies)

??????????????? return response

?

if __name__ == "__main__":

??? hc=HttpClient()

??? response=hc.request("post","http://39.106.41.29:8080/register/","form",'{"username":"xufengchai6","password":"xufengchai121","email":"xufengchai@qq.com"}')

??? print response.text

?

結果:ok

?

C:\Python27\python.exe D:/test/interfaceFramework_practice1/util/httpClient.py

{"username": "xufengchai6", "code": "01"}

?

Process finished with exit code 0

?

在工程下新建testData目錄,存放數據文件
inter_test_data.xlsx

?

?

這個數據文件可以說是本次接口框架的核心,文件中從每個測試用例sheet都代表一個接口,用例中設計了請求數據的格式、請求依賴數據的格式、檢查點、是否需要執(zhí)行、執(zhí)行結果、錯誤信息、響應數據、響應狀態(tài)碼等。

該文件的結構設計直接決定了框架的邏輯設計,程序首先會遍歷API sheet中的每一行,區(qū)分出需要執(zhí)行的接口用例,然后到對應的接口用例sheet中讀取請求數據,發(fā)送http請求,對響應做斷言和存儲并寫入結果,之后再進行下一個接口的處理;其中在處理當前接口用例時會有依賴數據(依賴于上一個接口的請求或響應)的處理,文件中會設置所需依賴數據的格式(模板)和請求數據的格式,程序根據請求數據、依賴數據列存儲的格式獲取到實際用于請求的數據,然后進行發(fā)送請求和后續(xù)的處理,如何做依賴數據的處理和存儲數據的處理是該框架的難點。

下面就一點一點寫主程序,看看需要做哪些處理,首先要讀取excel文件,需要excel文件的操作,那就把之前封裝的excel操作直接拿過來。

?

步驟3:封裝excel操作方法,讀取excel數據文件

在uti包下新建parseExcel.py

#encoding=utf-8

import openpyxl

from openpyxl.styles import Border,Side,Font

import time

?

class ParseExcel(object):

??? def __init__(self):

??????? self.workbook=None

??????? self.excelFile=None

??????? self.font=Font(color=None)

??????? self.colorDict={'red':'FFFF3030','green':'FF008B00'}

?

??? def loadWorkBook(self,excelPathAndName):

??????? #將excel文件加載到內存,并獲取其workbook對象

??????? try:

??????????? self.workbook=openpyxl.load_workbook(excelPathAndName)

??????? except Exception,e:

??????????? raise e

??????? self.excelFile=excelPathAndName

??????? return self.workbook

??? def getSheetByName(self,sheetName):

??????? try:

??????????? sheet=self.workbook[sheetName]

??????????? return sheet

??????? except Exception,e:

??????????? raise e

?

??? def getSheetByIndex(self,sheetIndex):

??????? try:

??????????? sheetName=self.workbook.sheetnames[sheetIndex]

??????? except Exception,e:

??????????? raise e

??????? sheet=self.workbook[sheetName]

??????? return sheet

?

??? def getTotalRowsNumber(self,sheet):

??????? return sheet.max_row

?

??? def getTotalColsNumber(self,sheet):

??????? return sheet.max_column

?

??? def getStartRowNumber(self,sheet):

??????? return sheet.min_row

?

??? def getStartColNumber(self,sheet):

??????? return sheet.min_column

?

??? def getSingleRow(self,sheet,rowNo):

??????? #獲取sheet中某一行,返回的是這一行所有的數據內容組成的tuple

??????? #下標從1開始,sheet.rows[1]表示第一行

??????? try:

??????????? return list(sheet.rows)[rowNo-1]

??????? except Exception,e:

??????????? raise e

?

??? def getSingleColumn(self,sheet,colNo):

??????? #獲取sheet中某一列,返回的是這一列所有的數據組成的tuple

??????? #下標從1開始,sheet.columns[1]表示第一列

??????? try:

??????????? return list(sheet.columns)[colNo-1]

??????? except Exception,e:

??????????? raise e

?

??? def getValueInCell(self,sheet,coordinate=None,rowNo=None,colNo=None):

??????? #根據單元格所在的位置索引獲取該單元格中的值,下標從1開始

??????? #sheet.cell(row=1,column=1).value,表示excel中第一行第一列的值

??????? if coordinate != None:#coordinate指坐標,如['A2']

??????????? try:

??????????????? return sheet[coordinate].value

??????????? except Exception,e:

??????????????? raise e

??????? elif coordinate is None and rowNo is not None and colNo is not None:

??????????? try:

??????????????? return sheet.cell(row=rowNo,column=colNo).value

??????????? except Exception,e:

??????????????? raise e

??????? else:

??????????? raise Exception("Argument exception! ")

?

??? def writeCell(self,sheet,content,coordinate=None,rowNo=None,colNo=None,color=None):

??????? #根據單元格在excel中的行、列號,或坐標值向單元格中寫入數據

??????? #color標識字體的顏色的名字,如red,green

??????? if coordinate:

??????????? try:

??????????????? sheet[coordinate].value=content

??????????????? if color:

??????????????????? sheet[coordinate].font=Font(color=self.colorDict[color])

??????????????? self.workbook.save(self.excelFile)

??????????? except Exception,e:

??????????????? raise e

??????? elif coordinate == None and rowNo is not None and colNo is not None:

??????????? try:

??????????????? sheet.cell(row=rowNo,column=colNo).value = content

??????????????? if color:

??????????????????? sheet.cell(row=rowNo,column=color).font=Font(color=self.colorDict[color])

??????????????? self.workbook.save(self.excelFile)

??????????? except Exception,e:

??????????????? raise e

??????? else:

??????????? raise Exception("Argument exception!")

?

??? def writeCurrentTimeInCell(self,sheet,coordinate=None,rowNo=None,colNo=None):

??????? #寫入當前時間,下標從1開始,如['A1']

??????? timeArray=time.localtime(time.time())

??????? currentTime=time.strftime("%Y-%m-%d %H:%M:%S",timeArray)

??????? if coordinate is not None:

??????????? try:

??????????????? sheet[coordinate].value=currentTime

??????????????? self.workbook.save(self.excelFile)

??????????? except Exception,e:

??????????????? raise e

??????? elif coordinate == None and rowNo is not None and colNo is not None:

??????????? try:

??????????????? sheet.cell(row == rowNo,column=colNo).value=currentTime

??????????????? self.workbook.save(self.excelFile)

??????????? except Exception,e:

??????????????? raise e

??????? else:

??????????? raise Exception("Argument exception!")

?

if __name__=='__main__':

??? pe=ParseExcel()

??? pe.loadWorkBook(r'd:\\testdata.xlsx')

??? sheetObj=pe.getSheetByName(u"API")

??? print u"用index號獲取sheet對象的名字:",pe.getSheetByIndex(0)

??? sheet=pe.getSheetByIndex(1)

??? print type(sheet)

??? print pe.getTotalRowsNumber(sheetObj)

??? print pe.getTotalColsNumber(sheetObj)

??? print pe.getTotalRowsNumber(sheet)

??? print pe.getTotalColsNumber(sheet)

??? #print list(sheet.rows)[1]

??? rows=pe.getSingleRow(sheet,1)

??? # for i in rows:

??? #???? if i.value:

??? #???????? print i.value

??? print pe.getValueInCell(sheetObj,'A1')

??? pe.writeCell(sheet,"xia","A2")

??? print pe.getValueInCell(sheetObj,"A2")

??? pe.writeCurrentTimeInCell(sheetObj,"A3")

結果:ok

C:\Python27\python.exe D:/test/interfaceFramework_practice1/util/ParseExcel.py

用index號獲取sheet對象的名字: <Worksheet "API">

<class 'openpyxl.worksheet.worksheet.Worksheet'>

13

13

3

1

a

xia

?

Process finished with exit code 0

?

在工程下新建config包,在該包下新建config.py文件用戶存儲公有變量
config.py:

#encoding=utf-8

import os

#項目的絕對路徑

projectDir=os.path.dirname(os.path.dirname(__file))

?

#數據文件的絕對路徑

file_path=projectDir + "\\testData\\inter_test_data.xlsx"

?

在testScript.py文件中讀取excel的數據
先把API sheet中的信息讀出來:

#encoding=utf-8

import requests

import json

from util.ParseExcel import *

from config.config import *

?

def testInterface():

??? pe=ParseExcel()

??? pe.loadWorkBook(file_path)

??? sheetObj=pe.getSheetByName(u"API")

??? executeList=pe.getSingleColumn(sheetObj,7)

??? #print executeList

??? for idx,cell in enumerate(executeList[1:],2):#第一行標題去掉,idx從2開始

??????? if cell.value == 'y':

??????????? #獲取需要執(zhí)行的接口所在的行對象

??????????? rowObj=pe.getSingleRow(sheetObj,idx)

??????????? apiName=rowObj[1].value

??????????? requestUrl=rowObj[2].value

??????????? requestMethod=rowObj[3].value

??????????? paramsType=rowObj[4].value

??????????? apiCaseSheetName=rowObj[5].value

??????????? print apiName,requestUrl,requestMethod,paramsType,apiCaseSheetName

?

?

if __name__ == "__main__":

??? testInterface()

結果:ok

C:\Python27\python.exe D:/test/interfaceFramework_practice1/testScripts/testScript.py

register http://39.106.41.29:8080/register/ post form 注冊接口用例

login http://39.106.41.29:8080/login/ post form 登錄接口用例

?

Process finished with exit code 0

?

可以看到在讀取需要執(zhí)行的行中每一列的內容時,用的索引號都是數字,這個不用說,肯定是要在公共變量中存一下的。

?

在config文件中把每個sheet中的列號用變量存起來

#API sheet中所需列號

API_apiName=2

API_requestUrl=3

API_requestMethod=4

API_paramsType=5

API_apiCaseSheetName=6

API_ifExecute=7

?

#接口用例sheet中所需列號

CASE_requestData=1

CASE_relyData=2

CASE_responseCode=3

CASE_responseData=4

CASE_dataStore=5

CASE_checkPoint=6

CASE_ifExecute=7

CASE_result=8

CASE_errorInfo=9

?

接著把caseSheet中的數據讀出來

#下一步讀取用例sheet表,準備執(zhí)行測試用例

caseSheetObj=pe.getSheetByName(apiCaseSheetName)#獲取用例sheet對象

caseExecuteCol=pe.getSingleColumn(caseSheetObj,CASE_ifExecute)#獲取用例sheet對象中需要執(zhí)行的列

#遍歷需要執(zhí)行的列

for c_idx,c_cell in enumerate(caseExecuteCol[1:],2):#標題行忽略,c_idx從2開始

??? if c_cell.value == 'y':

??????? #說明case行需要執(zhí)行

??????? caseRowObj=pe.getSingleRow(caseSheetObj,c_idx)

??????? requestData=caseRowObj[CASE_requestData-1].value

??????? relyData=caseRowObj[CASE_relyData-1].value

??????? dataStore=caseRowObj[CASE_dataStore-1].value

??????? checkPoint=caseRowObj[CASE_checkPoint-1].value

??????? #print requestData,relyData,dataStore,checkPoint

??????? #if relyData:#relyData列有值的話,需要獲取依賴數據

??????????? #發(fā)送接口數據之前,先做依賴數據的處理??????????

?

?

寫到這兒讓我們來分析一下這個框架的結構和邏輯,它是如何對每個接口進行測試和斷言的?這個問題想明白了,這個框架的核心就確定了。
先看下文檔中接口的信息:

在注冊接口中,請求數據RequestData直接給出了,那么把這列數據取出來,直接發(fā)送請求就可以了,然后把結果寫在responseData列,注冊接口響應參數有code和userid, userid是一個主鍵,唯一標識一個用戶,在checkPoint列設置檢查點,和響應code做對比,如果匹配00,就說明注冊接口請求成功了,把Result列寫入pass。

?

?

因為請求數據直接給出了,不需要依賴別的數據,那RelyData列置空,然后有個ResponseCode列需要寫一下請求的狀態(tài)碼,比如返回200,就寫200,然后看DataStore列,這一列是用來存儲接口請求的信息的,可以寫請求的參數信息,也可以寫響應的參數信息,這個存儲數據是干啥的呢,它是用來為其他接口請求做準備數據的;

比如登錄接口,在登錄之前,需要獲取用戶的用戶名和密碼,那它就需要從注冊接口的信息來獲取,可以在注冊接口的DataStore列把用戶名和密碼信息直接寫進去,如username:xiaxiaoxu,password:ksdfjlks,然后再運行登錄接口請求時,過來把數據取出來,直接發(fā)送請求就行了,登錄接口返回的參數有token和userid,這個token是查詢博文接口用的;

接下來我們再把各個接口的請求參數和響應參數列出來,然后來看下下游接口的請求數據是如何依賴上游接口的數據的。

注冊接口:

請求:

{"username": "xufengchai6", "password": "xufengchai121", "email": "xufengchai@qq.com"}

響應:

{"code": "00", "userid": 48}

---------------------------------------------------------------------------------------------------------------------------

登錄接口:

請求:

{"username": "xufengchai6", "password": "7f73a2e4d8b01b0f0f1062a59d4df635"}

這里的username、password依賴于注冊接口中的請求數據

響應:

{"token": "290cbf8f1438f3d8f56d9026604de336", "code": "00", "userid": 48, "login_time": "2018-08-05 10:22:05"}

---------------------------------------------------------------------------------------------------------------------------

新增博文:

請求:

{'userid':48,'token':'290cbf8f1438f3d8f56d9026604de336','title':'practice','content':'interface learn'}

這里的userid、token依賴于登錄接口中的響應數據

響應:

{"data": [{"content": "interface learn", "title": "practice"}], "code": "00", "userid": 48}

---------------------------------------------------------------------------------------------------------------------------

查詢用戶博文:

請求:

{"token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48}

這里的token、userid可以依賴于新增博文接口的響應數據,也可以依賴登錄于接口的響應數據

響應:

{"data": [{"update_time": null, "title": "practice", "content": "interface learn", "articleId": 2, "owner": 48, "posted_on": "2018-08-05 10:58:58"}, {"update_time": null, "title": "practice", "content": "interface learn", "articleId": 1, "owner": 48, "posted_on": "2018-08-05 10:35:33"}], "code": "00", "userid": 48}

---------------------------------------------------------------------------------------------------------------------------

修改博文:

請求:

{'userid':48,'token':'290cbf8f1438f3d8f56d9026604de336',"articleId":1,"title": "xiaxiaoxu test", "content": "interface learn xia"}

這里的articleId、title中的可以依賴于查詢用戶博文接口的響應數據,userid、token可以依賴于查詢用戶博文接口的請求數據

響應:

{"articleId": 1, "update_time": "2018-08-05 11:16:05", "code": "00", "userid": 48}

---------------------------------------------------------------------------------------------------------------------------

查詢博文內容:

請求:

'http://39.106.41.29:8080/getBlogContent/'+str(articleId)

這里的articleId可以依賴于查詢用戶博文接口的響應數據,也可以依賴于修改博文的請求數據,但是修改博文接口不一定會運行,依賴于查詢用戶博文接口會穩(wěn)妥一些

響應:

{"code": "00", "data": [{"update_time": "2018-08-05 11:16:05", "title": "xiaxiaoxu test", "content": "interface learn xia", "articleId": 1, "owner": 48, "posted_on": "2018-08-05 10:35:33"}]}

---------------------------------------------------------------------------------------------------------------------------

批量查詢博文內容:

請求:

http://localhost:8080/getBlogsContent/articleIds=1,2,3

這里的articleIds可以依賴于查詢用戶博文接口的響應數據

響應:

{"code": "00", "data": [{"update_time": "2018-08-05 11:16:05", "title": "xiaxiaoxu test", "content": "interface learn xia", "articleId": 1, "owner": 48, "posted_on": "2018-08-05 10:35:33"}, {"update_time": null, "title": "practice", "content": "interface learn", "articleId": 2, "owner": 48, "posted_on": "2018-08-05 10:58:58"}]}

?

通過上邊各個接口的數據依賴關系,可以看出某個接口在請求的之前,要先根據依賴關系到某個上游接口的請求或者響應數據中獲取需要的數據,那么怎么去把這個數據獲取到呢?以什么規(guī)則去獲取呢?把這兩個個問題解決了,我認為這個框架就成功了一半了!

為啥呢,因為我一半的時間都用來思考這兩個問題了,雖然事先已經知道了答案,但是為了透徹的理解其中的原理,花了很長時間來推理這個答案的合理性和必然性~~

對于這種框架的原理,我總是嘗試著把所有的細節(jié)都揉碎了來重新梳理,推理出每一個步驟的合理性,這樣會理解的更深一些。

?

初步的思路是每個接口在運行的時候把請求數據和響應數據都寫到文件里,然后下一個接口在訪問的時候去依賴接口中讀取請求數據或者響應數據,然后再把請求和響應數據寫到自己的sheet表中,以此類推,接著考慮一下實現的細節(jié),這個框架要兼顧多個接口的運行,每個接口的請求數據、存儲數據的方法需要用封裝的函數來進行處理,這就需要把這些接口的數據信息的獲取抽象出一個公用的方法,這個方法可以實現所有接口的數據處理,比如某個接口在獲取請求數據時,要先根據接口的請求參數設置一個依賴規(guī)則,指明每個參數需要到哪個接口的哪個用例的請求數據或者響應數據中,讀取哪個參數的值,每個參數可能需要到不同的接口中獲取數據,這個依賴規(guī)則需要給出具體的接口名、用例號(行號)、數據類型是請求的還是響應的,然后根據數據類型到不同的列號取值,取的時候,先找到單元格,把內容讀出來,轉成字典的格式,然后找所需的鍵值對,有的接口字典深度不止一層(如查詢接口),那就要再做一層處理,獲取完請求數據信息,就可以發(fā)送請求了,之后再把響應數據寫到文件中,后續(xù)接口可能會用到。

?

步驟4:封裝方法獲取請求數據

在action包下新建文件getRequestData.py:
getRequestData.py

# encoding=utf-8

?

from util.ParseExcel import *

import os

from config.config import *

import json

?

?

class GetRequestData(object):

??? def __init__(self):

??????? pass

?

??? @classmethod

??? def getRequestData(cls, relyRule):

??????? pe = ParseExcel()

??????? pe.loadWorkBook(file_path)

??????? requestData = {}

??????? # relySource = {"token": "", "userid": "","articleid":""}

??????? # relyRule = {"token":"userRegister->1->request","userid":"register->1->response","articleid":"userLogin->1->response->['data'][0]"}

??????? interDict = {"userRegister": "register",

???????????????????? "userLogin": "login",

???????????????????? "searchUserBlog": "search",

???????????????????? "modifyBlog": "modify"}

??????? dataTypeColDict = {"request": CASE_requestData,

?????????????????????????? "response": CASE_responseData}

???? ???# 根據接口名映射一個字典,對應接口sheet名稱

??????? # 獲取到依賴接口的sheet頁,case號(行號),請求列或者響應列號,

??????? # 然后到對應單元格取數據,轉成字典格式,

??????? # 取出里面對應層級的數據

??????? for key, value in relyRule.items():? # "articleid":"userLogin->1->response->['data'][0]"

??????????? print "key:value==>", key, ":", value

??????????? rList = value.split("->")

??????????? print "len(rList):", len(rList)

??????????? if len(rList) == 4:

??????????????? # 說明所需數據在依賴數據的第二層

??????????????? interfaceType, caseNo, dataType, dataKey = rList

??????????????? # print "interfaceType,caseNo,dataType,dataKey:",interfaceType,',',caseNo,',',dataType,',',dataKey

??????????????? # print "interDict[interfaceType]:",interDict[interfaceType]

??????????????? # print "dataTypeColDict[dataType]:",dataTypeColDict[dataType]

????????? ??????interSheetObj = pe.getSheetByName(interDict[interfaceType])

??????????????? # print "interSheetObj:",interSheetObj

??????????????? relyContent = json.loads(

??????????????????? pe.getValueInCell(interSheetObj, rowNo=int(caseNo) + 1, colNo=dataTypeColDict[dataType]))

??????????????? # print "relyContent:",relyContent

??????????????? # print "type(relyContent):",type(relyContent)

??????????????? command = "%s%s['%s']" % (relyContent, dataKey, key)

??????????????? # print "command:",command

??????????????? requestData[key] = eval(command)

??????????????? print "requestData-3:",requestData

??????????? elif len(rList) == 3:

??????????????? # 說明所需數據在依賴數據的第一層

??????????????? # "token":"userLogin->1->response"

??????????????? interfaceType, caseNo, dataType = rList

??????????????? # print "interfaceType,caseNo,dataType:",interfaceType,',',caseNo,',',dataType

??????????????? # print "interDict[interfaceType]:",interDict[interfaceType]

??????????????? # print "dataTypeColDict[dataType]:",dataTypeColDict[dataType]

??????????????? interSheetObj = pe.getSheetByName(interDict[interfaceType])

??????????????? # print "interSheetObj:",interSheetObj

??????????????? contentStr = '%s' % pe.getValueInCell(interSheetObj, rowNo=int(caseNo) + 1,

?????????????????? ???????????????????????????????????colNo=dataTypeColDict[dataType])

??????????????? print "contentStr:", contentStr

??????????????? print "type(contentStr):", type(contentStr)

??????????????? relyContent = json.loads(contentStr)

??????????????? print "relyContent:", relyContent

??????????????? # print "type(relyContent):",type(relyContent)

??????????????? command = "%s['%s']" % (relyContent, key)

??????????????? # print "command:",command

??????????????? requestData[key] = eval(command)

??????????????? print "requestData-1:",requestData

??????????? else:

??????????????? requestData[key] = value

??????? return requestData

?

?

if __name__ == "__main__":

??? relyRule = {"articleId": "searchUserBlog->1->response->['data'][0]", "token": "userLogin->1->response",

??????????????? "content": "xiaxiaoxu"}

print GetRequestData.getRequestData(relyRule)

?

結果:ok

C:\Python27\python.exe D:/test/interfaceFramework_practice1/action/getRequestData.py

key:value==> content : xiaxiaoxu

len(rList): 1

key:value==> token : userLogin->1->response

len(rList): 3

contentStr: {"token": "290cbf8f1438f3d8f56d9026604de336", "code": "00", "userid": 48, "login_time": "2018-08-05 10:22:05"}

type(contentStr): <type 'unicode'>

relyContent: {u'token': u'290cbf8f1438f3d8f56d9026604de336', u'code': u'00', u'userid': 48, u'login_time': u'2018-08-05 10:22:05'}

requestData-1: {'content': 'xiaxiaoxu', 'token': u'290cbf8f1438f3d8f56d9026604de336'}

key:value==> articleId : searchUserBlog->1->response->['data'][0]

len(rList): 4

requestData-3: {'content': 'xiaxiaoxu', 'token': u'290cbf8f1438f3d8f56d9026604de336', 'articleId': 2}

{'content': 'xiaxiaoxu', 'token': u'290cbf8f1438f3d8f56d9026604de336', 'articleId': 2}

?

Process finished with exit code 0

?

這種獲取請求數據方法的思路是,在每個接口中把請求的數據設置一個依賴的規(guī)則,用來指明所需的參數來自哪個接口的請求數據還是響應數據,然后程序根據這個依賴規(guī)則,去所依賴的地方獲取數據。

例如

relyRule={"articleId":"searchUserBlog->1->response->['data'][0]","token":"userLogin->1->response","content": "xiaxiaoxu"},

這個依賴規(guī)則是個json串,用json編輯器可以看到它的結構:

?

可以看到它有三個兄弟節(jié)點,代表該接口需要三個請求參數,每個兄弟節(jié)點下邊是這個參數所依賴的規(guī)則,比如"articleId":"searchUserBlog->1->response->['data'][0]",表示"articleId"這個參數依賴的數據是searchUserBlog接口的數據,具體是在searchUserBlog接口的第一個用例的響應數據中的[‘data’]對應的數據中的第1個articleId字段的值,其所依賴的接口數據存儲的格式也是json串的形式,可以轉成python的字典結構,這樣依賴規(guī)則的每一層數據都可以用作為字典的key取出對應的value值,這個value值又作為新一層字典來取值。

下面是searchUserBlog接口的響應數據的例子:

{"data": [{"update_time": null, "title": "practice", "content": "interface learn", "articleId": 2, "owner": 48, "posted_on": "2018-08-05 10:58:58"}, {"update_time": null, "title": "practice", "content": "interface learn", "articleId": 1, "owner": 48, "posted_on": "2018-08-05 10:35:33"}], "code": "00", "userid": 48}

需要注意的是,在每個接口獲取請求數據時,它所依賴的接口的數據要事先存在,否則就取不到數據了,所以,在處理完每個接口的請求后,需要把請求數據和響應數據寫入文件,以備后續(xù)接口使用。

下一步實現寫入文件的方法

?

步驟5:實現寫入文件的方法

在action包下新建write_test_result.py
write_test_result.py

#encoding=utf-8

from config import *

from util.ParseExcel import *

from action.getRequestData import *

import json

?

def write_result(wbObj,sheetObj,rowNum,requestData=None,responseData=None,errorKey = None):

??? try:

??????? if requestData:

??????????? #寫入請求數據

??????????? print "requestData-4:",requestData

??????????? print "type(requestData-4):",type(requestData)

??????????? wbObj.writeCell(sheet=sheetObj,content=requestData,rowNo=rowNum,colNo=CASE_requestData)

??????? if responseData:

??????????? #寫響應body

??????????? wbObj.writeCell(sheet=sheetObj,content=responseData,rowNo=rowNum,colNo=CASE_responseData)

??????? #寫校驗結果狀態(tài)列及錯誤信息列

??????? if errorKey:

??????????? wbObj.writeCell(sheet=sheetObj,content="failed",rowNo=rowNum,colNo=CASE_result)

??????????? wbObj.writeCell(sheet=sheetObj,content="%s" %errorKey,rowNo = rowNum,colNo=CASE_errorInfo)

??????? else:

??????????? wbObj.writeCell(sheetObj,content="pass",rowNo=rowNum,colNo=CASE_result)

??? except Exception,e:

??????? raise e

?

在主程序中調用該方法:
testScript.py:

#encoding=utf-8

import requests

import json

from util.ParseExcel import *

from util.httpClient import *

from config.config import *

from action.write_test_result import *

?

def testInterface():

??? parseE = ParseExcel()

??? parseE.loadWorkBook(file_path)

??? sheetObj = parseE.getSheetByName(u"API")

??? activeList = parseE.getSingleColumn(sheetObj, API_ifExecute)

??? for idx, cell in enumerate(activeList[1:], 2):

??????? if cell.value == 'y':

??????????? rowObj = parseE.getSingleRow(sheetObj, idx)

??????????? apiName = rowObj[API_apiName - 1].value

??????????? requestUrl = rowObj[API_requestUrl - 1].value

??????????? requestMethod = rowObj[API_requestMethod - 1].value

??????????? paramsType = rowObj[API_paramsType - 1].value

??????????? apiTestCaseFileName = rowObj[API_apiCaseSheetName - 1].value

??????????? # print apiName,requestUrl,requestMethod,paramsType,apiTestCaseFileName

??????????? # 下一步讀sheet表,準備執(zhí)行測試用例

??????????? print "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"

??????????? print "apiTestCaseFileName:", apiTestCaseFileName

??????????? caseSheetObj = parseE.getSheetByName(apiTestCaseFileName)

??????????? caseActiveObj = parseE.getSingleColumn(caseSheetObj, CASE_ifExecute)

????????? ??for c_idx, col in enumerate(caseActiveObj[1:], 2):

??????????????? if col.value == 'y':

??????????????????? caseRowObj = parseE.getSingleRow(caseSheetObj, c_idx)

??????????????????? relyRule = caseRowObj[CASE_relyRule - 1].value

??????????????????? print "relyRule:", relyRule

??????????????????? if relyRule:

??????????????????????? # 發(fā)送接口請求之前,先獲取請求數據

??????????????????????? requestData = json.dumps(GetRequestData.getRequestData(eval(relyRule)))

??????????????????????? print "requestData-2:", requestData

??????????????????????? write_result(parseE,caseSheetObj,c_idx,requestData=requestData)

??????????????????????? # print "print requestData Done!"

?

?

if __name__ == "__main__":

??? testInterface()

?

結果:ok

C:\Python27\python.exe D:/test/interfaceFramework_practice1/testScripts/testScript.py

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

apiTestCaseFileName: register

relyRule: None

relyRule: None

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

apiTestCaseFileName: login

relyRule: {"username":"userRegister->1->request","password":"userRegister->1->request"}

key:value==> username : userRegister->1->request

len(rList): 3

contentStr: {"username":"srsdcx01","password":"wcx123wac1","email":"wcx@qq.com"}

type(contentStr): <type 'unicode'>

relyContent: {u'username': u'srsdcx01', u'password': u'wcx123wac1', u'email': u'wcx@qq.com'}

requestData-1: {'username': u'srsdcx01'}

key:value==> password : userRegister->1->request

len(rList): 3

contentStr: {"username":"srsdcx01","password":"wcx123wac1","email":"wcx@qq.com"}

type(contentStr): <type 'unicode'>

relyContent: {u'username': u'srsdcx01', u'password': u'wcx123wac1', u'email': u'wcx@qq.com'}

requestData-1: {'username': u'srsdcx01', 'password': u'wcx123wac1'}

requestData-2: {"username": "srsdcx01", "password": "wcx123wac1"}

requestData-4: {"username": "srsdcx01", "password": "wcx123wac1"}

type(requestData-4): <type 'str'>

relyRule: {"username":"userRegister->2->request","password":"userRegister->2->request"}

key:value==> username : userRegister->2->request

len(rList): 3

contentStr: {"username":"wcd23x","password":"wcx123wac","email":"wcx@qq.com"}

type(contentStr): <type 'unicode'>

relyContent: {u'username': u'wcd23x', u'password': u'wcx123wac', u'email': u'wcx@qq.com'}

requestData-1: {'username': u'wcd23x'}

key:value==> password : userRegister->2->request

len(rList): 3

contentStr: {"username":"wcd23x","password":"wcx123wac","email":"wcx@qq.com"}

type(contentStr): <type 'unicode'>

relyContent: {u'username': u'wcd23x', u'password': u'wcx123wac', u'email': u'wcx@qq.com'}

requestData-1: {'username': u'wcd23x', 'password': u'wcx123wac'}

requestData-2: {"username": "wcd23x", "password": "wcx123wac"}

requestData-4: {"username": "wcd23x", "password": "wcx123wac"}

type(requestData-4): <type 'str'>

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

apiTestCaseFileName: search

relyRule: {"token":"userLogin->1->response","userid":"userLogin->1->response"}

key:value==> token : userLogin->1->response

len(rList): 3

contentStr: {"token": "290cbf8f1438f3d8f56d9026604de336", "code": "00", "userid": 48, "login_time": "2018-08-05 10:22:05"}

type(contentStr): <type 'unicode'>

relyContent: {u'token': u'290cbf8f1438f3d8f56d9026604de336', u'code': u'00', u'userid': 48, u'login_time': u'2018-08-05 10:22:05'}

requestData-1: {'token': u'290cbf8f1438f3d8f56d9026604de336'}

key:value==> userid : userLogin->1->response

len(rList): 3

contentStr: {"token": "290cbf8f1438f3d8f56d9026604de336", "code": "00", "userid": 48, "login_time": "2018-08-05 10:22:05"}

type(contentStr): <type 'unicode'>

relyContent: {u'token': u'290cbf8f1438f3d8f56d9026604de336', u'code': u'00', u'userid': 48, u'login_time': u'2018-08-05 10:22:05'}

requestData-1: {'token': u'290cbf8f1438f3d8f56d9026604de336', 'userid': 48}

requestData-2: {"token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48}

requestData-4: {"token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48}

type(requestData-4): <type 'str'>

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

apiTestCaseFileName: modify

relyRule: {"userid":"searchUserBlog->1->response","token":"searchUserBlog->1->request","articleId":"searchUserBlog->1->response->['data'][0]","title":"searchUserBlog->1->response->['data'][0]","content":"interface learn xia"}

key:value==> content : interface learn xia

len(rList): 1

key:value==> articleId : searchUserBlog->1->response->['data'][0]

len(rList): 4

requestData-3: {'content': 'interface learn xia', 'articleId': 2}

key:value==> token : searchUserBlog->1->request

len(rList): 3

contentStr: {"token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48}

type(contentStr): <type 'unicode'>

relyContent: {u'token': u'290cbf8f1438f3d8f56d9026604de336', u'userid': 48}

requestData-1: {'content': 'interface learn xia', 'token': u'290cbf8f1438f3d8f56d9026604de336', 'articleId': 2}

key:value==> userid : searchUserBlog->1->response

len(rList): 3

contentStr: {"data": [{"update_time": null, "title": "practice", "content": "interface learn", "articleId": 2, "owner": 48, "posted_on": "2018-08-05 10:58:58"}, {"update_time": null, "title": "practice", "content": "interface learn", "articleId": 1, "owner": 48, "posted_on": "2018-08-05 10:35:33"}], "code": "00", "userid": 48}

type(contentStr): <type 'unicode'>

relyContent: {u'userid': 48, u'code': u'00', u'data': [{u'update_time': None, u'title': u'practice', u'content': u'interface learn', u'articleId': 2, u'owner': 48, u'posted_on': u'2018-08-05 10:58:58'}, {u'update_time': None, u'title': u'practice', u'content': u'interface learn', u'articleId': 1, u'owner': 48, u'posted_on': u'2018-08-05 10:35:33'}]}

requestData-1: {'content': 'interface learn xia', 'userid': 48, 'token': u'290cbf8f1438f3d8f56d9026604de336', 'articleId': 2}

key:value==> title : searchUserBlog->1->response->['data'][0]

len(rList): 4

requestData-3: {'content': 'interface learn xia', 'userid': 48, 'token': u'290cbf8f1438f3d8f56d9026604de336', 'articleId': 2, 'title': u'practice'}

requestData-2: {"content": "interface learn xia", "userid": 48, "token": "290cbf8f1438f3d8f56d9026604de336", "articleId": 2, "title": "practice"}

requestData-4: {"content": "interface learn xia", "userid": 48, "token": "290cbf8f1438f3d8f56d9026604de336", "articleId": 2, "title": "practice"}

type(requestData-4): <type 'str'>

?

Process finished with exit code 0

?

文件中的請求數據已經寫進去了,先忽略響應數據

?

?

發(fā)現忘了處理passord的加密過程了,在getRequestdata.py中處理一下
在util包下新建md5_encrypt.py用戶加密處理
md5_encrypt.py:

#encoding=utf-8

import hashlib

?

def md5_encrypt(text):

??? m5 = hashlib.md5()

??? m5.update(text)

??? value = m5.hexdigest()

??? return value

?

if __name__ == "__main__":

print md5_encrypt("xiaxiaoxu")

?

結果:ok

D:\test_python\interfaceFramework>python md5_encrypt.py

a2f93c01757358aa9c3ee4372a2f4eca

修改getRequestData.py文件加入密碼加密處理:

# encoding=utf-8

?

from util.ParseExcel import *

import os

from config.config import *

import json

from util.md5_encrypt import *

?

class GetRequestData(object):

??? def __init__(self):

??????? pass

?

??? @classmethod

??? def getRequestData(cls, relyRule):

??????? pe = ParseExcel()

??????? pe.loadWorkBook(file_path)

??????? requestData = {}

??????? # relySource = {"token": "", "userid": "","articleid":""}

??????? # relyRule = {"token":"userRegister->1->request","userid":"register->1->response","articleid":"userLogin->1->response->['data'][0]"}

??????? interDict = {"userRegister": "register",

???????????? ????????"userLogin": "login",

???????????????????? "searchUserBlog": "search",

???????????????????? "modifyBlog": "modify"}

??????? dataTypeColDict = {"request": CASE_requestData,

?????????????????????????? "response": CASE_responseData}

??????? # 根據接口名映射一個字典,對應接口sheet名稱

??????? # 獲取到依賴接口的sheet頁,case號(行號),請求列或者響應列號,

??????? # 然后到對應單元格取數據,轉成字典格式,

??????? # 取出里面對應層級的數據

??????? for key, value in relyRule.items():? # "articleid":"userLogin->1->response->['data'][0]"

??????????? print "key:value==>", key, ":", value

??????????? rList = value.split("->")

??????????? print "len(rList):", len(rList)

??????????? if len(rList) == 4:

??????????????? # 說明所需數據在依賴數據的第二層

??????????????? interfaceType, caseNo, dataType, dataKey = rList

??????????????? # print "interfaceType,caseNo,dataType,dataKey:",interfaceType,',',caseNo,',',dataType,',',dataKey

??????????????? # print "interDict[interfaceType]:",interDict[interfaceType]

??????????????? # print "dataTypeColDict[dataType]:",dataTypeColDict[dataType]

??????????????? interSheetObj = pe.getSheetByName(interDict[interfaceType])

??????????????? # print "interSheetObj:",interSheetObj

??????????????? relyContent = json.loads(

??????????????????? pe.getValueInCell(interSheetObj, rowNo=int(caseNo) + 1, colNo=dataTypeColDict[dataType]))

??????????????? # print "relyContent:",relyContent

??????????????? # print "type(relyContent):",type(relyContent)

??????????????? command = "%s%s['%s']" % (relyContent, dataKey, key)

??????????????? # print "command:",command

??????????????? requestData[key] = eval(command)

??????????????? print "requestData-3:",requestData

??????????? elif len(rList) == 3:

??????????????? # 說明所需數據在依賴數據的第一層

??????????????? # "token":"userLogin->1->response"

??????????????? interfaceType, caseNo, dataType = rList

??????????????? # print "interfaceType,caseNo,dataType:",interfaceType,',',caseNo,',',dataType

??????????????? # print "interDict[interfaceType]:",interDict[interfaceType]

??????????????? # print "dataTypeColDict[dataType]:",dataTypeColDict[dataType]

??????????????? interSheetObj = pe.getSheetByName(interDict[interfaceType])

??????????????? # print "interSheetObj:",interSheetObj

??????????????? contentStr = '%s' % pe.getValueInCell(interSheetObj, rowNo=int(caseNo) + 1,

????????????????????????????????????????????????????? colNo=dataTypeColDict[dataType])

??????????????? print "contentStr:", contentStr

??????????????? print "type(contentStr):", type(contentStr)

??????????????? relyContent = json.loads(contentStr)

??????? ????????print "relyContent:", relyContent

??????????????? # print "type(relyContent):",type(relyContent)

??????????????? command = "%s['%s']" % (relyContent, key)

??????????????? # print "command:",command

??????????????? print "key:eval(command):",key,eval(command)

??????????????? requestData[key] = md5_encrypt(eval(command)) if key == "password" else eval(command)

??????????????? print "requestData-1:",requestData

??????????? else:

??????????????? requestData[key] = value

??????? return requestData

?

?

if __name__ == "__main__":

??? relyRule = {"articleId": "searchUserBlog->1->response->['data'][0]", "password": "userRegister->1->request",

??????????????? "content": "xiaxiaoxu"}

??? print GetRequestData.getRequestData(relyRule)

?

結果:ok

C:\Python27\python.exe D:/test/interfaceFramework_practice1/action/getRequestData.py

key:value==> content : xiaxiaoxu

len(rList): 1

key:value==> password : userRegister->1->request

len(rList): 3

contentStr: {"username":"srsdcx01","password":"wcx123wac1","email":"wcx@qq.com"}

type(contentStr): <type 'unicode'>

relyContent: {u'username': u'srsdcx01', u'password': u'wcx123wac1', u'email': u'wcx@qq.com'}

key:eval(command): password wcx123wac1

requestData-1: {'content': 'xiaxiaoxu', 'password': 'd85fb67e312ed3a589951720a6f3b079'}

key:value==> articleId : searchUserBlog->1->response->['data'][0]

len(rList): 4

requestData-3: {'content': 'xiaxiaoxu', 'password': 'd85fb67e312ed3a589951720a6f3b079', 'articleId': 2}

{'content': 'xiaxiaoxu', 'password': 'd85fb67e312ed3a589951720a6f3b079', 'articleId': 2}

?

Process finished with exit code 0

?

至此,已經實現了獲取請求數據,封裝了http請求的方法,那么把請求數據用http請求的方式發(fā)送給服務器就完成了接口的請求過程,下面在主程序中加入發(fā)送請求和寫入結果的處理

?

步驟 6:處理發(fā)送請求和寫入結果

在主程序中添加http請求處理,并把請求數據和響應數據寫入文件
testScript.py:

#encoding=utf-8

import requests

import json

from util.ParseExcel import *

from util.httpClient import *

from config.config import *

from action.write_test_result import *

from action.check_result import *

def testInterface():

??? parseE = ParseExcel()

??? parseE.loadWorkBook(file_path)

??? sheetObj = parseE.getSheetByName(u"API")

??? activeList = parseE.getSingleColumn(sheetObj, API_ifExecute)

??? for idx, cell in enumerate(activeList[1:], 2):

??????? if cell.value == 'y':

??????????? rowObj = parseE.getSingleRow(sheetObj, idx)

???????? ???apiName = rowObj[API_apiName - 1].value

??????????? requestUrl = rowObj[API_requestUrl - 1].value

??????????? requestMethod = rowObj[API_requestMethod - 1].value

??????????? paramsType = rowObj[API_paramsType - 1].value

??????????? apiTestCaseFileName = rowObj[API_apiCaseSheetName - 1].value

??????????? # print apiName,requestUrl,requestMethod,paramsType,apiTestCaseFileName

??????????? # 下一步讀sheet表,準備執(zhí)行測試用例

??????????? print "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"

??????????? print "apiTestCaseFileName:", apiTestCaseFileName

??????????? caseSheetObj = parseE.getSheetByName(apiTestCaseFileName)

??????????? caseActiveObj = parseE.getSingleColumn(caseSheetObj, CASE_ifExecute)

??????????? for c_idx, col in enumerate(caseActiveObj[1:], 2):

??????????? ????if col.value == 'y':

??????????????????? caseRowObj = parseE.getSingleRow(caseSheetObj, c_idx)

??????????????????? relyRule = caseRowObj[CASE_relyRule - 1].value

??????????????????? checkPoint=caseRowObj[CASE_checkPoint-1].value

??????????????????? print "relyRule:", relyRule

?

??????????????????? if relyRule:

??????????????????????? # 發(fā)送接口請求之前,先獲取請求數據

??????????????????????? requestData = json.dumps(GetRequestData.getRequestData(eval(relyRule)))

??????????????????????? print "requestData-2:", requestData

??????????????????? else:

??????????????????????? requestData=caseRowObj[CASE_requestData-1].value

??????????????????????? print "requestData without relyRule:",requestData,type(requestData)

???? ???????????????hc = HttpClient()

??????????????????? print "requestMethod, requestUrl, paramsType, requestData:"

??????????????????? print requestMethod, requestUrl, paramsType, requestData

??????????????????? response = hc.request(requestMethod=requestMethod,

???????????????????????????????????????????? requestUrl=requestUrl,

???????????????????????????????????????????? paramsType=paramsType,

???????????????????????????????????????????? requestData=requestData

???????????????????????????????????????????? )

??????????????????? print "#############response.text##############:",response.text

??????????????????? if response.status_code ==200:

??????????????????????? responseData=response.text

??????????????????????? print "responseData:",responseData

????????? ??????????????write_result(parseE,caseSheetObj,c_idx,requestData=requestData,responseData=responseData)

?

結果: ok

?

D:\test_python\interfaceFramework>python testScript.py

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

apiTestCaseFileName: searchUserBlog

relyRule: {"token":"userLogin->1->response","userid":"userLogin->1->response"}

key:value==> token : userLogin->1->response

len(rList): 3

contentStr: {"token": "290cbf8f1438f3d8f56d9026604de336", "code": "00", "userid": 48, "login_time": "2018-08-15 12:20:06"}

type(contentStr): <type 'unicode'>

relyContent: {u'token': u'290cbf8f1438f3d8f56d9026604de336', u'code': u'00', u'userid': 48, u'login_time': u'2018-08-15 12:20:06'}

key:eval(command): token 290cbf8f1438f3d8f56d9026604de336

requestData-1: {'token': u'290cbf8f1438f3d8f56d9026604de336'}

key:value==> userid : userLogin->1->response

len(rList): 3

contentStr: {"token": "290cbf8f1438f3d8f56d9026604de336", "code": "00", "userid": 48, "login_time": "2018-08-15 12:20:06"}

type(contentStr): <type 'unicode'>

relyContent: {u'token': u'290cbf8f1438f3d8f56d9026604de336', u'code': u'00', u'userid': 48, u'login_time': u'2018-08-15 12:20:06'}

key:eval(command): userid 48

requestData-1: {'token': u'290cbf8f1438f3d8f56d9026604de336', 'userid': 48}

requestData-2: {"token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48}

requestMethod, requestUrl, paramsType, requestData:

post http://39.106.41.29:8080/getBlogsOfUser/ form {"token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48}

#############response.text##############: {"code": "03", "params": {"token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48}}

responseData: {"code": "03", "params": {"token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48}}

requestData-4: {"token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48}

type(requestData-4): <type 'str'>

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

apiTestCaseFileName: addBlog

relyRule: {"userid":"userLogin->1->response","token":"userLogin->1->response","titile":"xiaxiaoxu's blog","content":"keep learning"}

key:value==> content : keep learning

len(rList): 1

key:value==> token : userLogin->1->response

len(rList): 3

contentStr: {"token": "290cbf8f1438f3d8f56d9026604de336", "code": "00", "userid": 48, "login_time": "2018-08-15 12:20:06"}

type(contentStr): <type 'unicode'>

relyContent: {u'token': u'290cbf8f1438f3d8f56d9026604de336', u'code': u'00', u'userid': 48, u'login_time': u'2018-08-15 12:20:06'}

key:eval(command): token 290cbf8f1438f3d8f56d9026604de336

requestData-1: {'content': 'keep learning', 'token': u'290cbf8f1438f3d8f56d9026604de336'}

key:value==> userid : userLogin->1->response

len(rList): 3

contentStr: {"token": "290cbf8f1438f3d8f56d9026604de336", "code": "00", "userid": 48, "login_time": "2018-08-15 12:20:06"}

type(contentStr): <type 'unicode'>

relyContent: {u'token': u'290cbf8f1438f3d8f56d9026604de336', u'code': u'00', u'userid': 48, u'login_time': u'2018-08-15 12:20:06'}

key:eval(command): userid 48

requestData-1: {'content': 'keep learning', 'token': u'290cbf8f1438f3d8f56d9026604de336', 'userid': 48}

key:value==> titile : xiaxiaoxu's blog

len(rList): 1

requestData-2: {"content": "keep learning", "token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48, "titile": "xiaxiaoxu's blog"}

requestMethod, requestUrl, paramsType, requestData:

post http://39.106.41.29:8080/create/ form {"content": "keep learning", "token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48, "titile": "xiaxiaoxu's blog"}

#############response.text##############: {"code": "03", "params": {"content": "keep learning", "token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48, "titile": "xiaxiaoxu's blog"}}

responseData: {"code": "03", "params": {"content": "keep learning", "token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48, "titile": "xiaxiaoxu's blog"}}

requestData-4: {"content": "keep learning", "token": "290cbf8f1438f3d8f56d9026604de336", "userid": 48, "titile": "xiaxiaoxu's blog"}

type(requestData-4): <type 'str'>

?

D:\test_python\interfaceFramework>python testScript.py

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

apiTestCaseFileName: register

relyRule: None

requestData without relyRule: {"username":"xufengchai6","password":"xufengchai121","email":"xufengchai@qq.com"} <type 'unicode'>

requestMethod, requestUrl, paramsType, requestData:

post http://39.106.41.29:8080/register/ form {"username":"xufengchai6","password":"xufengchai121","email":"xufengchai@qq.com"}

#############response.text##############: {"code": "00", "userid": 17}

responseData: {"code": "00", "userid": 17}

requestData-4: {"username":"xufengchai6","password":"xufengchai121","email":"xufengchai@qq.com"}

type(requestData-4): <type 'unicode'>

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

apiTestCaseFileName: login

relyRule: {"username":"userRegister->1->request","password":"userRegister->1->request"}

key:value==> username : userRegister->1->request

len(rList): 3

contentStr: {"username":"xufengchai6","password":"xufengchai121","email":"xufengchai@qq.com"}

type(contentStr): <type 'unicode'>

relyContent: {u'username': u'xufengchai6', u'password': u'xufengchai121', u'email': u'xufengchai@qq.com'}

key:eval(command): username xufengchai6

requestData-1: {'username': u'xufengchai6'}

key:value==> password : userRegister->1->request

len(rList): 3

contentStr: {"username":"xufengchai6","password":"xufengchai121","email":"xufengchai@qq.com"}

type(contentStr): <type 'unicode'>

relyContent: {u'username': u'xufengchai6', u'password': u'xufengchai121', u'email': u'xufengchai@qq.com'}

key:eval(command): password xufengchai121

requestData-1: {'username': u'xufengchai6', 'password': '7f73a2e4d8b01b0f0f1062a59d4df635'}

requestData-2: {"username": "xufengchai6", "password": "7f73a2e4d8b01b0f0f1062a59d4df635"}

requestMethod, requestUrl, paramsType, requestData:

post http://39.106.41.29:8080/login/ form {"username": "xufengchai6", "password": "7f73a2e4d8b01b0f0f1062a59d4df635"}

#############response.text##############: {"token": "5e546324ba91858b26216d399dee33e1", "code": "00", "userid": 17, "login_time": "2018-08-16 12:17:59"}

responseData: {"token": "5e546324ba91858b26216d399dee33e1", "code": "00", "userid": 17, "login_time": "2018-08-16 12:17:59"}

requestData-4: {"username": "xufengchai6", "password": "7f73a2e4d8b01b0f0f1062a59d4df635"}

type(requestData-4): <type 'str'>

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

apiTestCaseFileName: addBlog

relyRule: {"userid":"userLogin->1->response","token":"userLogin->1->response","titile":"xiaxiaoxu's blog","content":"keep learning"}

key:value==> content : keep learning

len(rList): 1

key:value==> token : userLogin->1->response

len(rList): 3

contentStr: {"token": "5e546324ba91858b26216d399dee33e1", "code": "00", "userid": 17, "login_time": "2018-08-16 12:17:59"}

type(contentStr): <type 'unicode'>

relyContent: {u'token': u'5e546324ba91858b26216d399dee33e1', u'code': u'00', u'userid': 17, u'login_time': u'2018-08-16 12:17:59'}

key:eval(command): token 5e546324ba91858b26216d399dee33e1

requestData-1: {'content': 'keep learning', 'token': u'5e546324ba91858b26216d399dee33e1'}

key:value==> userid : userLogin->1->response

len(rList): 3

contentStr: {"token": "5e546324ba91858b26216d399dee33e1", "code": "00", "userid": 17, "login_time": "2018-08-16 12:17:59"}

type(contentStr): <type 'unicode'>

relyContent: {u'token': u'5e546324ba91858b26216d399dee33e1', u'code': u'00', u'userid': 17, u'login_time': u'2018-08-16 12:17:59'}

key:eval(command): userid 17

requestData-1: {'content': 'keep learning', 'token': u'5e546324ba91858b26216d399dee33e1', 'userid': 17}

key:value==> titile : xiaxiaoxu's blog

len(rList): 1

requestData-2: {"content": "keep learning", "token": "5e546324ba91858b26216d399dee33e1", "userid": 17, "titile": "xiaxiaoxu's blog"}

requestMethod, requestUrl, paramsType, requestData:

post http://39.106.41.29:8080/create/ form {"content": "keep learning", "token": "5e546324ba91858b26216d399dee33e1", "userid": 17, "titile": "xiaxiaoxu's blog"}

#############response.text##############: {"code": "03", "params": {"content": "keep learning", "token": "5e546324ba91858b26216d399dee33e1", "userid": 17, "titile": "xiaxiaoxu's blog"}}

responseData: {"code": "03", "params": {"content": "keep learning", "token": "5e546324ba91858b26216d399dee33e1", "userid": 17, "titile": "xiaxiaoxu's blog"}}

requestData-4: {"content": "keep learning", "token": "5e546324ba91858b26216d399dee33e1", "userid": 17, "titile": "xiaxiaoxu's blog"}

type(requestData-4): <type 'str'>

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

apiTestCaseFileName: searchUserBlog

relyRule: {"token":"userLogin->1->response","userid":"userLogin->1->response"}

key:value==> token : userLogin->1->response

len(rList): 3

contentStr: {"token": "5e546324ba91858b26216d399dee33e1", "code": "00", "userid": 17, "login_time": "2018-08-16 12:17:59"}

type(contentStr): <type 'unicode'>

relyContent: {u'token': u'5e546324ba91858b26216d399dee33e1', u'code': u'00', u'userid': 17, u'login_time': u'2018-08-16 12:17:59'}

key:eval(command): token 5e546324ba91858b26216d399dee33e1

requestData-1: {'token': u'5e546324ba91858b26216d399dee33e1'}

key:value==> userid : userLogin->1->response

len(rList): 3

contentStr: {"token": "5e546324ba91858b26216d399dee33e1", "code": "00", "userid": 17, "login_time": "2018-08-16 12:17:59"}

type(contentStr): <type 'unicode'>

relyContent: {u'token': u'5e546324ba91858b26216d399dee33e1', u'code': u'00', u'userid': 17, u'login_time': u'2018-08-16 12:17:59'}

key:eval(command): userid 17

requestData-1: {'token': u'5e546324ba91858b26216d399dee33e1', 'userid': 17}

requestData-2: {"token": "5e546324ba91858b26216d399dee33e1", "userid": 17}

requestMethod, requestUrl, paramsType, requestData:

post http://39.106.41.29:8080/getBlogsOfUser/ form {"token": "5e546324ba91858b26216d399dee33e1", "userid": 17}

#############response.text##############: {"data": [], "code": "00", "userid": 17}

responseData: {"data": [], "code": "00", "userid": 17}

requestData-4: {"token": "5e546324ba91858b26216d399dee33e1", "userid": 17}

type(requestData-4): <type 'str'>

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

apiTestCaseFileName: modify

文件截圖:

?

?

?

至此,實現了獲取請求數據,發(fā)送請求,把請求數據和響應數據寫入文件

下一步,處理接口結果的校驗,判斷接口返回數據是否正確

?

步驟7:校驗接口返回結果

在action包下新建check_result.py用于處理結果的校驗
check_result.py:

#encoding=utf-8

import re

?

class CheckResult(object):

??? def __init__(self):

??????? pass

?

??? @classmethod

??? def checkResult(cls,responseData,checkPoint):

??????? # {"code":"00","userid":{"value":"\w+"}, "articleId":{"type":"N"}}

??????? # responseObj ={"code": "01", "userid": 12, "id": "12"}

??????? errorKey={}

??????? for key,value in checkPoint.items():

??????????? if isinstance(value,(str,unicode)):

??????????????? #說明是等值校驗

??????????????? if responseData[key] != value:

??????????????????? errorKey[key] = responseData[key]

??????????? elif isinstance(value,dict):

??????????????? #說明是需要通過正則表達式去校驗

??????????????? sourceData=responseData[key]#接口返回的真實值

??????????????? if value.has_key("value"):

??????????????????? #說明是通過正則校驗

??????????????????? regStr=value["value"]

??????????????????? rg=re.match(regStr,"%s" %sourceData)

??????????????????? if not rg:

??????????????????????? errorKey[key] = sourceData

??????????????? elif value.has_key("type"):

??????????????????? #說明是校驗數據類型

??????????????????? typeStr=value["type"]

??????????????????? if typeStr == "N":

??????????????????????? #說明是整形

??????????????????????? if not isinstance(sourceData,(int,long)):

??????????????????????????? errorKey[key] = sourceData

??????? return errorKey

?

if __name__ == '__main__':

??? resouceData={"code":"01","userid":12,"id":"12"}

??? checkPoint={"code":"00","userid":{"type":"N","id":{"value":"\d+"}}}

??? print CheckResult.checkResult(resouceData,checkPoint)

?

?

結果:ok

C:\Python27\python.exe D:/test/interfaceFramework_practice1/action/check_result.py

{'code': '01'}

?

Process finished with exit code 0

?

修改主程序,添加寫入校驗結果部分
testScript.py:

#encoding=utf-8

import requests

import json

from util.ParseExcel import *

from util.httpClient import *

from config.config import *

from action.write_test_result import *

from action.check_result import *

def testInterface():

??? parseE = ParseExcel()

??? parseE.loadWorkBook(file_path)

??? sheetObj = parseE.getSheetByName(u"API")

??? activeList = parseE.getSingleColumn(sheetObj, API_ifExecute)

??? for idx, cell in enumerate(activeList[1:], 2):

??????? if cell.value == 'y':

??????????? rowObj = parseE.getSingleRow(sheetObj, idx)

??????????? apiName = rowObj[API_apiName - 1].value

??????????? requestUrl = rowObj[API_requestUrl - 1].value

??????????? requestMethod = rowObj[API_requestMethod - 1].value

??????????? paramsType = rowObj[API_paramsType - 1].value

??????????? apiTestCaseFileName = rowObj[API_apiCaseSheetName - 1].value

??????????? # print apiName,requestUrl,requestMethod,paramsType,apiTestCaseFileName

??????????? # 下一步讀sheet表,準備執(zhí)行測試用例

??????????? print "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"

??????????? print "apiTestCaseFileName:", apiTestCaseFileName

??????????? caseSheetObj = parseE.getSheetByName(apiTestCaseFileName)

??????????? caseActiveObj = parseE.getSingleColumn(caseSheetObj, CASE_ifExecute)

??????????? for c_idx, col in enumerate(caseActiveObj[1:], 2):

??????????????? if col.value == 'y':

??????????????????? caseRowObj = parseE.getSingleRow(caseSheetObj, c_idx)

??????????????????? relyRule = caseRowObj[CASE_relyRule - 1].value

??????????????????? checkPoint=json.loads(caseRowObj[CASE_checkPoint-1].value)

??????????????????? print "relyRule:", relyRule

?

??????????????????? if relyRule:

??????????????????????? # 發(fā)送接口請求之前,先獲取請求數據

??????????????????????? requestData = json.dumps(GetRequestData.getRequestData(eval(relyRule)))

??????????????????????? print "requestData-2:", requestData

?????????? ?????????else:

??????????????????????? requestData=caseRowObj[CASE_requestData-1].value

??????????????????????? print "requestData without relyRule:",requestData,type(requestData)

??????????????????? hc = HttpClient()

??????????????????? print "requestMethod, requestUrl, paramsType, requestData:"

??????????????????? print requestMethod, requestUrl, paramsType, requestData

??????????????????? response = hc.request(requestMethod=requestMethod,

???????????????????????????????????????????? requestUrl=requestUrl,

???????????????????????????????????????????? paramsType=paramsType,

???????????????????????????????????????????? requestData=requestData

???????????????????????????????????????????? )

??????????????????? print "#############response.text##############:",response.text

??????????????????? if response.status_code ==200:

??????????????????????? responseData=response.text

??????????????????????? print "responseData-1,type(responsedata-1):",responseData,type(responseData)

??????????????????????? errorKey=CheckResult.checkResult(json.loads(responseData),checkPoint)

??????????????????????? write_result(parseE,caseSheetObj,c_idx,requestData=str(requestData),responseData=str(responseData),errorKey=errorKey)

?

?

??????????????????? else:

??????????????????????? print "接口請求異常,狀態(tài)碼為:",response.status_code

??????????????? else:

??????????????????? print "接口用例被忽略執(zhí)行"

??????? else:

??????????? print "API測試被忽略"

?

?

?

if __name__ == "__main__":

??? testInterface()

結果:ok

C:\Python27\python.exe D:/test/interfaceFramework_practice1/testScripts/testScript.py

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

apiTestCaseFileName: register

relyRule: None

requestData without relyRule: {"username":"xufengchai6","password":"xufengchai121","email":"xufengchai@qq.com"} <type 'unicode'>

requestMethod, requestUrl, paramsType, requestData:

post http://39.106.41.29:8080/register/ form {"username":"xufengchai6","password":"xufengchai121","email":"xufengchai@qq.com"}

#############response.text##############: {"username": "xufengchai6", "code": "01"}

responseData-1,type(responsedata-1): {"username": "xufengchai6", "code": "01"} <type 'unicode'>

requestData-4: {"username":"xufengchai6","password":"xufengchai121","email":"xufengchai@qq.com"}

type(requestData-4): <type 'str'>

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

apiTestCaseFileName: login

relyRule: {"username":"userRegister->1->request","password":"userRegister->1->request"}

key:value==> username : userRegister->1->request

len(rList): 3

contentStr: {"username":"xufengchai6","password":"xufengchai121","email":"xufengchai@qq.com"}

type(contentStr): <type 'unicode'>

relyContent: {u'username': u'xufengchai6', u'password': u'xufengchai121', u'email': u'xufengchai@qq.com'}

key:eval(command): username xufengchai6

requestData-1: {'username': u'xufengchai6'}

key:value==> password : userRegister->1->request

len(rList): 3

contentStr: {"username":"xufengchai6","password":"xufengchai121","email":"xufengchai@qq.com"}

type(contentStr): <type 'unicode'>

relyContent: {u'username': u'xufengchai6', u'password': u'xufengchai121', u'email': u'xufengchai@qq.com'}

key:eval(command): password xufengchai121

requestData-1: {'username': u'xufengchai6', 'password': '7f73a2e4d8b01b0f0f1062a59d4df635'}

requestData-2: {"username": "xufengchai6", "password": "7f73a2e4d8b01b0f0f1062a59d4df635"}

requestMethod, requestUrl, paramsType, requestData:

post http://39.106.41.29:8080/login/ form {"username": "xufengchai6", "password": "7f73a2e4d8b01b0f0f1062a59d4df635"}

#############response.text##############: {"token": "c7cf5ab52e674f2449f22579d294426d", "code": "00", "userid": 2, "login_time": "2018-08-17 21:27:10"}

responseData-1,type(responsedata-1): {"token": "c7cf5ab52e674f2449f22579d294426d", "code": "00", "userid": 2, "login_time": "2018-08-17 21:27:10"} <type 'unicode'>

requestData-4: {"username": "xufengchai6", "password": "7f73a2e4d8b01b0f0f1062a59d4df635"}

type(requestData-4): <type 'str'>

API測試被忽略

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

apiTestCaseFileName: searchUserBlog

relyRule: {"token":"userLogin->1->response","userid":"userLogin->1->response"}

key:value==> token : userLogin->1->response

len(rList): 3

contentStr: {"token": "c7cf5ab52e674f2449f22579d294426d", "code": "00", "userid": 2, "login_time": "2018-08-17 21:27:10"}

type(contentStr): <type 'unicode'>

relyContent: {u'token': u'c7cf5ab52e674f2449f22579d294426d', u'code': u'00', u'userid': 2, u'login_time': u'2018-08-17 21:27:10'}

key:eval(command): token c7cf5ab52e674f2449f22579d294426d

requestData-1: {'token': u'c7cf5ab52e674f2449f22579d294426d'}

key:value==> userid : userLogin->1->response

len(rList): 3

contentStr: {"token": "c7cf5ab52e674f2449f22579d294426d", "code": "00", "userid": 2, "login_time": "2018-08-17 21:27:10"}

type(contentStr): <type 'unicode'>

relyContent: {u'token': u'c7cf5ab52e674f2449f22579d294426d', u'code': u'00', u'userid': 2, u'login_time': u'2018-08-17 21:27:10'}

key:eval(command): userid 2

requestData-1: {'token': u'c7cf5ab52e674f2449f22579d294426d', 'userid': 2}

requestData-2: {"token": "c7cf5ab52e674f2449f22579d294426d", "userid": 2}

requestMethod, requestUrl, paramsType, requestData:

post http://39.106.41.29:8080/getBlogsOfUser/ form {"token": "c7cf5ab52e674f2449f22579d294426d", "userid": 2}

#############response.text##############: {"data": [], "code": "00", "userid": 2}

responseData-1,type(responsedata-1): {"data": [], "code": "00", "userid": 2} <type 'unicode'>

requestData-4: {"token": "c7cf5ab52e674f2449f22579d294426d", "userid": 2}

type(requestData-4): <type 'str'>

API測試被忽略

?

Process finished with exit code 0

?

Excel結果:寫入請求數據、響應數據、結果ok

由于這種方式沒有用到responseCode和dataStore列,所以刪掉了,之后換種思路時會用到,到時再加上

?

?

轉載于:https://www.cnblogs.com/xiaxiaoxu/p/9523049.html

總結

以上是生活随笔為你收集整理的搭建接口自动化测试框架详细过程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

热99久久精品 | 久草在线视频首页 | 夜夜视频资源 | 992tv在线成人免费观看 | 欧美激情片在线观看 | av日韩中文 | 最近日本mv字幕免费观看 | 成人免费观看av | 久久欧美精品 | 毛片基地黄久久久久久天堂 | 国产精品毛片一区二区 | 91探花国产综合在线精品 | 美女网站在线播放 | av免费看看 | 在线观看你懂的网址 | 色视频在线观看 | 国产精品一区电影 | 日韩精品免费一区二区在线观看 | 日韩欧美视频在线观看免费 | 国产香蕉视频在线观看 | 91污在线观看 | 中文字幕精品在线 | 中文av在线免费观看 | 成人一级在线观看 | 91片黄在线观 | 欧美日韩在线播放一区 | 午夜三级大片 | 97视频在线观看成人 | 精品久久久久久久久久久久久久久久 | 成 人 黄 色 视频免费播放 | 精品久久久久一区二区国产 | 欧美精品久久久久久久 | 2023亚洲精品国偷拍自产在线 | 国产一线二线三线在线观看 | 久久a v视频 | 亚洲国产精品500在线观看 | 人人干人人添 | 91系列在线| 国产成人精品久久久 | 天堂av观看 | 成年人黄色大片在线 | 亚洲自拍av在线 | 蜜臀一区二区三区精品免费视频 | 99久久精品无码一区二区毛片 | 开心婷婷色 | 国产精品一区二区av日韩在线 | 国产日韩精品在线观看 | 国产在线视频在线观看 | 一区二区在线不卡 | 国产午夜在线观看视频 | 亚洲狠狠婷婷综合久久久 | 亚洲综合狠狠干 | av黄网站 | 综合激情网... | 国产亚洲综合在线 | 超碰97中文 | 亚洲欧洲美洲av | 亚洲精品乱码久久久久久蜜桃91 | 久久a免费视频 | 国产亚洲精品女人久久久久久 | 亚洲成av人片在线观看香蕉 | 色姑娘综合天天 | 久久综合久久综合这里只有精品 | 国产成人精品久久久久蜜臀 | 特级毛片aaa | 91综合视频在线观看 | 成人国产精品久久久 | 天天干天天拍天天操天天拍 | 亚洲精品乱码久久久久 | 免费观看性生交 | 亚洲a成人v | 爱爱av网站 | 精品久久久久久久久亚洲 | 黄色www免费| 热久久影视 | 麻豆视频国产精品 | 亚洲视频大全 | 色五婷婷 | 91精品久久香蕉国产线看观看 | 久久国产午夜精品理论片最新版本 | 国产女人40精品一区毛片视频 | 国产美女在线观看 | 国内精品久久久久久久 | 在线免费观看黄色小说 | 日本久久精品视频 | 99精品免费在线 | 国产看片 色 | 欧美韩国日本在线 | 欧美在线一级片 | 国产精品国内免费一区二区三区 | 精品国产电影一区二区 | 伊人中文在线 | 91福利试看 | 日韩av在线资源 | 成人黄色中文字幕 | 国产精品乱码在线 | 国产精品原创在线 | av高清一区二区三区 | 9999毛片| 婷色在线| 久久av免费| 国产亚洲婷婷 | 国产美女在线精品免费观看 | 天天操 夜夜操 | 日日操日日 | 五月婷婷开心中文字幕 | 欧美亚洲另类在线视频 | 97超级碰碰 | 亚洲日本国产精品 | 中文字幕人成乱码在线观看 | 成人午夜电影免费在线观看 | avwww在线 | 岛国av在线 | 美女网色 | 国产麻豆电影在线观看 | 黄色小说网站在线 | 日韩 国产| 国产aa免费视频 | 国产高清不卡在线 | 中文字幕中文字幕中文字幕 | 国产97视频 | 97成人精品视频在线播放 | 99看视频在线观看 | 最新av网址在线观看 | 欧美人交a欧美精品 | 丁香视频五月 | 97国产一区二区 | 成人免费看黄 | 视频一区二区三区视频 | 99热这里只有精品国产首页 | 亚洲欧美日韩国产精品一区午夜 | 91精品在线看 | 日韩性片| 欧美视频二区 | 在线黄色av | 久久人操 | 国产精品精品久久久 | 日韩一区二区三区视频在线 | 成人网444ppp | 中文字幕欧美日韩va免费视频 | 日韩在线观看一区 | 国产精品久久久久免费a∨ 欧美一级性生活片 | 色橹橹欧美在线观看视频高清 | 欧美一区二区三区免费观看 | 亚洲精选在线观看 | 免费日韩av电影 | 91视频在线免费看 | 久久99精品久久久久久久久久久久 | 亚洲乱码久久久 | 91av影视 | 久久99久久久久 | 婷婷亚洲激情 | 日韩精品一区二区三区第95 | av中文字幕在线播放 | 91精品婷婷国产综合久久蝌蚪 | 中文字幕高清有码 | 国产精品综合在线观看 | 国产女v资源在线观看 | 日日爽天天 | 免费中文字幕在线观看 | 久久久久久久99 | 国产色中涩 | 免费试看一区 | 免费观看第二部31集 | 黄色av电影在线观看 | 国产资源中文字幕 | 国产手机视频在线观看 | 啪啪午夜免费 | 日本韩国精品在线 | 狠狠色狠狠色综合日日小说 | 在线免费观看视频 | 中文字幕在线观看视频一区二区三区 | 精品美女视频 | 91亚色在线观看 | 激情综合五月 | 国产精品综合在线 | 天天干天天操天天入 | 97精品视频在线 | 国产美女视频网站 | 亚洲高清在线视频 | 亚洲免费精品一区二区 | 久久久久久免费毛片精品 | www.玖玖玖 | 久久精品视频免费 | 久久高清国产视频 | 亚洲色图色| 日韩一级片观看 | 欧美另类性 | 在线香蕉视频 | 九九视频热 | 91av九色 | 精品久久久久久久久久久院品网 | 成人啪啪18免费游戏链接 | 日韩av电影免费在线观看 | 91精品久久久久久综合乱菊 | 91视频-88av | 国产精品黄色影片导航在线观看 | 亚在线播放中文视频 | 97在线播放| 五月激情片 | 免费观看视频黄 | www日| 国产99久久久久久免费看 | 在线视频1卡二卡三卡 | 国产亚州av | 黄色三级免费 | 在线观看精品视频 | 日韩电影一区二区三区在线观看 | 99精品视频在线观看视频 | 国产片免费在线观看视频 | 亚州国产精品 | 中文字幕在线看视频 | 亚洲情婷婷 | 久久夜靖品 | 91av官网 | 在线观看黄污 | 色中色综合 | 日韩精品欧美专区 | 99久久久国产精品免费观看 | 久久久精品国产一区二区电影四季 | 久久草av| 丰满少妇在线观看资源站 | 久久免费公开视频 | 亚洲天天在线 | 久久免费精品一区二区三区 | 国产精品久久久久毛片大屁完整版 | 国产123区在线观看 国产精品麻豆91 | 亚洲精品福利在线 | 国产精品一区二区av影院萌芽 | 一区二区三区在线不卡 | 久久国产精品视频 | 欧美一性一交一乱 | 精品在线观看一区二区 | 人人澡人人爽欧一区 | 天天天天天天天操 | 蜜臀aⅴ精品一区二区三区 久久视屏网 | 在线小视频你懂得 | 日韩精品免费在线观看视频 | 久久这里| 毛片在线播放网址 | 激情视频免费在线 | www夜夜 | 色婷婷久久 | 国产精品福利小视频 | 伊人资源站 | 手机av电影在线观看 | 麻豆视频免费入口 | av在线免费观看黄 | 国产麻豆精品久久一二三 | 福利视频一区二区 | 在线观看激情av | 成人亚洲网 | 日韩草比| japanesexxxxfreehd乱熟 | 激情在线免费视频 | 免费在线视频一区二区 | 天天·日日日干 | 亚洲无线视频 | 不卡中文字幕在线 | 久久综合久久综合久久综合 | 国产日产精品久久久久快鸭 | 午夜国产一区 | 99视频99 | 91豆麻精品91久久久久久 | 日韩综合视频在线观看 | 成年人在线 | 五月婷婷中文 | 四虎4hu永久免费 | 97超碰人| av看片在线观看 | 日韩一级理论片 | 综合色影院 | 91精品国产福利在线观看 | 成人一区电影 | 高清在线一区 | 亚洲精品日韩在线观看 | 久久伦理影院 | 国内精品视频一区二区三区八戒 | 操久久免费视频 | 亚洲毛片久久 | 精品国产一区二区三区久久久蜜臀 | 国产精品久久久久久久免费观看 | 国产视频日韩视频欧美视频 | av色图天堂网 | 九色91在线视频 | 91精品国产成人 | www.com久久久| 欧美成人基地 | 日韩一区二区久久 | av在线在线 | 国产精品国产亚洲精品看不卡 | 欧美一区二区免费在线观看 | 婷婷综合伊人 | 在线观看视频日韩 | 亚洲成a人片77777kkkk1在线观看 | 在线 成人| 免费a网址| 天天操天天艹 | 亚洲成人黄色网址 | 亚洲国产精品资源 | 97超碰免费在线 | 麻豆国产精品va在线观看不卡 | 99热最新 | 在线观看日本高清mv视频 | 黄色av免费 | 96av视频| 亚洲国产影院av久久久久 | 欧美日本不卡视频 | 中文字幕国产精品一区二区 | 91av原创| 色综合中文字幕 | 中文在线免费看视频 | 久久久九色精品国产一区二区三区 | 久久久久草 | 久久国产免费看 | 中文字幕免费观看全部电影 | 97香蕉视频 | 色综合久久久久综合体桃花网 | 在线观看中文 | 成人av资源| 国产精品大片免费观看 | 国产精品午夜av | 九七视频在线 | 中文字幕中文字幕在线中文字幕三区 | 日韩理论电影网 | 婷婷激情综合 | 成人黄在线 | 国产高清精品在线观看 | 五月婷婷国产 | 亚洲国产精品久久久久婷婷884 | 欧美激情另类文学 | 69亚洲视频| 日韩欧美精选 | 午夜精品久久久久久中宇69 | 操久在线| 美女视频是黄的免费观看 | 日韩免费视频网站 | 91久色蝌蚪 | 国产超碰在线 | 麻豆国产视频 | 成年人在线免费看视频 | 在线精品一区二区 | 日韩一区二区免费视频 | 91精品国产成人www | 亚洲综合成人婷婷小说 | 久久久久欠精品国产毛片国产毛生 | 九九热在线精品视频 | 欧美久久99| 色爱成人网 | 麻豆免费精品视频 | 天天拍天天色 | 亚洲精品在线观 | 欧美精品在线观看免费 | 成人动漫一区二区三区 | 国产精品美女视频 | 国产丝袜美腿在线 | 国产在线资源 | 久久久久久久久久久精 | 一区二区三区高清在线观看 | 久久伊人精品一区二区三区 | 天天射射天天 | 久久精品一二三区白丝高潮 | 亚洲开心色 | 日本aaaa级毛片在线看 | 久久99精品久久只有精品 | 在线中文字幕一区二区 | av中文字幕网站 | 免费麻豆 | 日批视频 | 欧美日韩国产精品一区二区 | 天天干天天射天天插 | 亚洲综合在线视频 | 狠狠操影视| 在线观看黄色免费视频 | 国产婷婷久久 | 国产精品久久久久久久久久久杏吧 | 国产精品久久久777 成人手机在线视频 | 精品在线一区二区 | 97日日碰人人模人人澡分享吧 | 国产精品毛片一区二区在线 | 色婷婷狠狠操 | 国产精品视频免费看 | 国产 视频 高清 免费 | 91欧美日韩国产 | 国产在线观看午夜 | 精品国产一区二区三区av性色 | 久草久草视频 | 国产糖心vlog在线观看 | 国产成人99久久亚洲综合精品 | 91麻豆操| 欧美日韩在线看 | 亚洲综合色播 | 五月在线视频 | 亚洲综合在线五月 | 玖玖精品在线 | 久久精品精品电影网 | 久久久久久亚洲精品 | 色婷五月| 手机成人免费视频 | 在线免费观看黄网站 | 久久精彩| 中午字幕在线 | 国产操在线 | 欧美日韩调教 | av中文字幕在线看 | 日韩有码在线观看视频 | 中文字幕av日韩 | www.五月天色| 免费福利视频网 | 色婷婷在线视频 | 国产视频精品在线 | www激情网 | 91激情视频在线观看 | 亚洲永久国产精品 | 午夜精品久久久久久久99婷婷 | 区一区二区三区中文字幕 | 国产精品乱码久久久久 | 99精品一区二区三区 | 亚洲精品午夜国产va久久成人 | 99精品国产一区二区 | 五月婷婷网站 | 激情综合网色播五月 | 96超碰在线| 狠狠色丁香婷婷综合基地 | 怡红院久久 | 91毛片在线观看 | 日韩电影黄色 | 精品久久一区二区 | 国产96av | 免费视频久久久久 | 午夜视频一区二区 | 激情五月六月婷婷 | 欧美日韩免费看 | 国产精品青草综合久久久久99 | 亚洲视频99 | 国产精选在线观看 | 国产精品毛片一区 | 天堂视频一区 | 在线韩国电影免费观影完整版 | free,性欧美 九九交易行官网 | 久久短视频 | 国产手机免费视频 | 69视频国产 | av黄色成人 | 狠狠操导航 | 久久伊人精品一区二区三区 | 少妇18xxxx性xxxx片 | 亚洲精品国产日韩 | 久久8精品 | 国产成人性色生活片 | 天天操福利视频 | 黄色网www| 日韩黄色免费在线观看 | 91成人精品视频 | 一区二区三区在线免费播放 | 欧美色婷| a√资源在线 | 免费看毛片在线 | 成人一区二区三区在线观看 | 日韩三级免费观看 | 天天射天天射天天射 | 黄色的视频网站 | 久热色超碰 | 欧美成人按摩 | 欧美日韩在线视频观看 | 日韩一级成人av | 国产日产精品一区二区三区四区的观看方式 | 欧美a在线看 | 久久精品日产第一区二区三区乱码 | 久久国产a| 婷婷社区五月天 | 国产午夜一级毛片 | 亚洲天天摸日日摸天天欢 | 国产免费又粗又猛又爽 | 精品久久片 | 伊人热| 日韩欧美视频一区 | 人人爱人人爽 | 97电影在线看视频 | 色吊丝av中文字幕 | 国产精品6999成人免费视频 | 黄色的网站在线 | 精品视频成人 | 日一日干一干 | 日韩欧美在线一区二区 | 在线亚洲日本 | 7777精品伊人久久久大香线蕉 | 人人艹人人 | 美女视频黄免费的 | 久久黄色免费 | 久久亚洲精品国产亚洲老地址 | 国产精品午夜在线观看 | 狠狠躁夜夜a产精品视频 | 中文字幕资源在线观看 | 久久九九网站 | 91九色在线观看 | 日韩视频一区二区三区在线播放免费观看 | 亚洲成人999 | 久久成人国产精品免费软件 | 99c视频高清免费观看 | 美女国产精品 | 在线免费黄色 | 久久久久久久99精品免费观看 | 97精品国产一二三产区 | 免费在线观看av | 国产18精品乱码免费看 | 国产高清区 | 黄色1级大片 | 日韩特级黄色片 | 91成熟丰满女人少妇 | 亚洲激情综合 | 亚洲欧美经典 | 久草青青在线观看 | 欧美精品乱码久久久久久按摩 | 久久精品99国产精品酒店日本 | 麻豆免费精品视频 | 99久久精品免费一区 | 午夜在线国产 | 在线播放精品一区二区三区 | 干干夜夜 | 日本不卡一区二区三区在线观看 | 在线观看www91 | 91精品入口 | 亚洲国产黄色片 | 超碰97av在线 | 国产一区二区久久久久 | 免费精品在线视频 | 九九视频一区 | 成年人免费观看在线视频 | 久久精品www人人爽人人 | 国产美女黄网站免费 | 777奇米四色 | 91传媒91久久久 | 色97在线 | 99re久久资源最新地址 | 天天天综合网 | 日本久久久久久科技有限公司 | www.夜夜操.com | 亚洲成人精品久久 | 国产高清在线免费观看 | 国产精品久久久久久av | 91免费网址 | 97视频精品 | 欧美高清视频不卡网 | 精品在线视频一区 | 91高清免费看 | 狠狠躁日日躁狂躁夜夜躁av | 国产美腿白丝袜足在线av | 天天做夜夜做 | 久久99视频| 日韩精品欧美视频 | 中文字幕一区二区在线播放 | 中文字幕传媒 | 日韩特级毛片 | 亚洲综合五月 | 国产99久久久欧美黑人 | 日韩免费电影一区二区 | 免费看wwwwwwwwwww的视频 久久久久久99精品 91中文字幕视频 | 中文日韩在线 | 国产亚洲精品久久19p | 亚洲人人爱 | 国产色爽 | 一区二区三区 中文字幕 | 中文资源在线观看 | 色wwww| 91精品啪在线观看国产 | 国产精品永久 | 国产美女精品视频 | www.xxxx欧美 | 国产 色 | 视频直播国产精品 | 欧美一级看片 | 久久精品二区 | 日韩视频一区二区在线 | 亚洲视频在线播放 | 日韩av在线资源 | 免费高清在线观看成人 | 91色蜜桃 | 亚洲第一区在线观看 | 精品亚洲va在线va天堂资源站 | 国产手机在线 | 午夜精品一区二区三区四区 | 久久久精品网 | 黄色一级网 | 国产在线视频一区二区三区 | 黄av免费 | 久久99热这里只有精品 | 99久久精品免费看国产 | 国产精品麻豆一区二区三区 | 亚洲第一区在线观看 | 国产美女精品人人做人人爽 | 黄色大片av | 综合在线色 | 久久黄色免费视频 | 98超碰人人 | 中文字幕日本特黄aa毛片 | 最近更新好看的中文字幕 | 人人看人人爱 | 中文字幕在线免费看 | 天天操夜夜曰 | 久久国色夜色精品国产 | 日批在线观看 | 国产99久久久国产精品 | 国产精品永久久久久久久久久 | 欧美午夜激情网 | 日韩中文字幕电影 | 日日骑 | 午夜久久久久久久久久影院 | 久久极品 | 日韩精品第一区 | 99综合久久 | 啪嗒啪嗒免费观看完整版 | 在线视频观看成人 | 美女视频免费一区二区 | 久久69精品 | 日韩免费不卡av | 亚洲人成免费网站 | 欧美日韩观看 | 日本性动态图 | 国产区在线视频 | 国产成人久久av | 在线免费看黄网站 | 天天看天天操 | 国产精品免费看久久久8精臀av | 91色九色| 日本护士三级少妇三级999 | 91麻豆精品国产 | 天天摸日日摸人人看 | 精品视频免费久久久看 | 天天操夜夜操 | 亚洲一区欧美精品 | 日韩色一区二区三区 | 182午夜在线观看 | 黄色的视频 | 国产免费三级在线观看 | 日韩免费电影一区二区三区 | 天天天干天天射天天天操 | 超碰97中文 | 免费日韩在线 | 久久99国产精品久久99 | 亚洲精品视频在线 | 天天操比| 午夜精品一区二区国产 | 久久成人高清 | 一区二区激情 | 中文字幕在线看人 | 免费看黄在线看 | 国产精品久久久久影视 | 91.dizhi永久地址最新 | 2023天天干| 久久精品观看 | 公与妇乱理三级xxx 在线观看视频在线观看 | 91免费看黄 | 国产麻豆精品一区 | 国产99久久99热这里精品5 | 国产午夜精品在线 | 最近更新好看的中文字幕 | 国产美女视频免费观看的网站 | 97久久久免费福利网址 | 99久久精品国产一区 | 超碰在线最新网址 | 成人在线免费看视频 | 欧美成年黄网站色视频 | 国产香蕉视频在线播放 | 亚洲一级免费观看 | 天天艹日日干 | av电影在线观看 | 五月综合婷 | 亚洲精品视频在线免费 | 一区二区三区在线播放 | 日韩免费一级电影 | 一区二区三区 中文字幕 | 日本中文字幕免费观看 | 成人永久免费 | 欧美成人按摩 | 不卡av在线 | 日本动漫做毛片一区二区 | 夜夜操网站 | 精品一区二区三区香蕉蜜桃 | 久久精品一级片 | 我要色综合天天 | 亚洲人人射 | 久一网站 | 亚洲国产欧美在线看片xxoo | 亚洲人人爱 | 这里只有精品视频在线 | 日韩av三区 | 狠狠色丁香婷综合久久 | 亚洲男男gaygay无套 | 特级毛片在线 | 激情欧美在线观看 | 亚洲日本va在线观看 | 美女黄视频免费 | 久久久久久激情 | 国产精品自产拍在线观看蜜 | 欧美成人手机版 | 婷婷丁香在线 | 亚洲另类xxxx | 天天翘av | 毛片一级免费一级 | 一区二区视 | www91在线| 国产在线 一区二区三区 | 欧美精品亚州精品 | 欧美另类xxxx | 日日夜夜婷婷 | 国产一区在线观看免费 | 色婷婷www | av综合网址 | 中文字幕乱在线伦视频中文字幕乱码在线 | 成人免费观看完整版电影 | 国产99免费视频 | 欧美精品视 | 日韩高清在线一区二区三区 | 国产3p视频 | 麻豆成人精品 | 日韩精品免费在线视频 | 国产乱视频 | 久久久久国产a免费观看rela | 九色精品免费永久在线 | 国产精品手机看片 | 国产999在线 | 丰满少妇麻豆av | 国产精品久久久久国产a级 激情综合中文娱乐网 | 久久xx视频 | 丁香5月婷婷久久 | 一区二区三区在线免费观看视频 | 亚洲精品国偷拍自产在线观看蜜桃 | 四虎在线免费观看视频 | 亚洲欧美日韩国产一区二区三区 | 国产中文字幕视频在线观看 | 亚洲午夜精 | 黄色成人小视频 | 在线观看麻豆av | 日本 在线 视频 中文 有码 | 久久精品—区二区三区 | 国精产品一二三线999 | 精品国产色 | 最近中文国产在线视频 | 日韩xxx视频 | 中文字幕第一页在线视频 | 黄网站免费大全入口 | 亚洲一级性 | 91在线免费播放 | 99久久婷婷国产综合精品 | av网址最新 | 美女视频网站久久 | av资源在线看| 草久久久久 | 免费观看性生活大片 | 色婷婷欧美 | 97精品电影院 | 色综合天天色综合 | 99视频偷窥在线精品国自产拍 | 国产日韩精品一区二区 | 亚洲成人av在线电影 | 人人爱人人添 | 久久免费高清视频 | 中文字幕av影院 | 免费网站黄色 | 色天天综合网 | 国产精品video | www,黄视频 | 黄色成人av在线 | 天天草天天草 | avav片| 国产精品一区二区无线 | 日韩网站在线观看 | 亚洲午夜精品久久久久久久久久久久 | 日韩一区二区三区高清免费看看 | 五月婷婷综合久久 | 奇米影视777影音先锋 | 中文字幕在线中文 | 亚洲国产网址 | 丁香婷婷综合网 | 国产黄色一级片 | 国产成人精品三级 | 亚州精品天堂中文字幕 | 国内精品在线一区 | 蜜桃视频精品 | 丰满少妇高潮在线观看 | 蜜臀av网站 | 久久久久久国产精品 | 久草精品电影 | 免费高清看电视网站 | 免费观看一区二区 | 国产黄色片网站 | 夜夜夜夜猛噜噜噜噜噜初音未来 | 国产精品美女久久久 | 日韩一级片网址 | 一级国产视频 | 成年人在线免费看视频 | av色网站| 一区二区三区 亚洲 | 精品国产一区二区三区久久久蜜月 | 色视频在线看 | 久久久久久久久毛片 | 在线亚洲观看 | 日本精品视频网站 | www.在线观看av| 五月天中文在线 | 国产精品亚 | 91成人免费看片 | 日韩理论片在线观看 | www久久国产| 日韩视频欧美视频 | 亚洲2019精品| 国产精品久久久久久婷婷天堂 | www.狠狠操.com | 亚洲天堂自拍视频 | 天无日天天操天天干 | 亚洲第一av在线播放 | 免费av福利 | 美女一二三区 | 国产成人精品一区二区三区福利 | 色网免费观看 | www.在线观看av | 国产区网址 | 四虎国产精品成人免费影视 | 亚洲三级网 | 91麻豆操 | 日韩一区二区三区免费电影 | 国产99在线播放 | av福利在线看 | 最新色站| 一区二区三区四区五区六区 | 丰满少妇久久久 | 欧美另类老妇 | 亚洲精品日韩在线观看 | 在线观看日韩一区 | 国产剧情久久 | 精品毛片在线 | 亚洲人成人99网站 | 色99网| 欧美另类一二三四区 | 日日爽天天操 | 这里只有精彩视频 | 黄色1级大片 | 天天玩天天干天天操 | 91成人在线看 | 国产成人久久精品亚洲 | 久久av影视 | 国产亚洲精品久久久久久网站 | 久久久久久久精 | 久久手机精品视频 | 三级动图 | 超碰97成人 | 亚洲国产精品免费 | 91亚洲精品久久久蜜桃借种 | 久久中文字幕在线视频 | 五月婷婷av | 日本精品va在线观看 | 在线观看日韩精品 | 国产中文字幕久久 | 国产精品igao视频网网址 | 亚洲成人av一区二区 | 久草在线网址 | 久久久精品网站 | 麻豆影视网 | 精品一区二区三区四区在线 | 国产精品一区二区三区在线 | 国产精品区在线观看 | 精油按摩av | 五月婷在线视频 | 国产免费xvideos视频入口 | 日韩网站在线播放 | 精品视频97| 久久免费99精品久久久久久 | 久久精品官网 | 韩国av免费在线观看 | 最新av网址大全 | 亚洲精区二区三区四区麻豆 | 久久久人| 久久精品99国产精品日本 | 色婷婷狠狠操 | 免费在线一区二区三区 | 日韩免费播放 | www在线观看视频 | 狠狠狠的干 | 国产视频二区三区 | 欧美一级性视频 | 亚洲天堂网站视频 | 国产婷婷久久 | 国产精品久久久久久久久毛片 | 国产免费专区 | 免费看国产黄色 | 成年人在线看片 | 超碰国产人人 | 国产欧美久久久精品影院 | 成人av免费 | 日韩精品一区二区三区电影 | 成人免费视频网站在线观看 | av资源网在线播放 | 亚洲黄色网络 | 日本不卡123区 | 日b视频国产 | 热re99久久精品国产66热 | 91成人在线看| www久久精品 | 日本女人在线观看 | 青青网视频| 国产91全国探花系列在线播放 | 五月婷婷中文网 | 亚洲综合色激情五月 | 6699私人影院 | 在线网站黄 | 天天操天天射天天爱 | 精品国产一区二区三区不卡 | 综合激情网... | 91福利在线导航 | 美女视频黄是免费的 | 免费观看完整版无人区 | 成 人 黄 色视频免费播放 | 免费黄色激情视频 | 男女精品久久 | 国产免费小视频 | 日韩免费av片 | 亚洲国产中文字幕在线 | 天天干天天干天天干 | 欧美一级专区免费大片 | 日韩精品视频免费看 | 国产黄色免费电影 | 欧美成人黄色片 | 国产精品手机在线观看 | 国产91在 | 最新av网站在线观看 | 欧美精品黑人性xxxx | 亚洲激情电影在线 | 91成人区| 91亚洲永久精品 | 欧美日韩久久一区 | 精品久久久一区二区 | 国产麻豆精品一区二区 | 色爱区综合激月婷婷 | 精品999在线观看 | 午夜免费电影院 | 啪啪午夜免费 | 狠狠干 狠狠操 | 久久久久久久av麻豆果冻 | 国产二区精品 | 午夜av在线播放 | 免费国产亚洲视频 | 九九久久精品视频 | 叶爱av在线 | 丁香花在线观看视频在线 | 色噜噜色噜噜 | 亚洲精品日韩一区二区电影 | 亚洲成人av片 | 国产日韩欧美在线 | 天堂av最新网址 | 免费高清在线一区 | 在线观看视频你懂的 | 视频在线在亚洲 | 国产高清黄色 | 亚洲国产三级在线观看 | 99色视频在线| 伊人中文在线 | 中文字幕丝袜一区二区 | 精品国内自产拍在线观看视频 | 超碰97在线人人 | 亚洲综合狠狠干 | 伊人春色电影网 | 色婷婷狠狠五月综合天色拍 | 国产香蕉久久精品综合网 | 色婷婷在线播放 | 中文字幕在线人 | 综合久久久久 | 午夜精品久久久久久久久久久 | 手机在线中文字幕 | 日韩成人邪恶影片 | 日韩精品欧美专区 | 久久五月网 | 69国产盗摄一区二区三区五区 | 色av资源网 | 在线国产激情视频 | 天天看天天操 | 天天操夜夜看 | 日韩字幕| 九九热精| 日韩a在线播放 | 国产黄在线 | 欧美精品一区在线 | 国产美女视频一区 | 久久99精品一区二区三区三区 | 成人在线电影观看 | 91成人免费视频 | 91av视频在线播放 | 日韩在线视频播放 | 久久99热精品 | 久久激情视频网 | 久久视频国产精品免费视频在线 | 亚洲视频h | 美女福利视频 | 麻豆手机在线 | 中文字幕日韩免费视频 | 免费男女羞羞的视频网站中文字幕 | 国产黄色片网站 | 99精品在线播放 |