练习搭建接口自动化测试框架详细过程
Posted xiaxiaoxu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了练习搭建接口自动化测试框架详细过程相关的知识,希望对你有一定的参考价值。
练习搭建接口自动化测试框架(文中所用接口信息、框架思路来自光荣之路培训学校,有意者请搜索光荣之路公众号咨询详细内容)
在设计接口测试框架前,先来弄清楚接口测试怎么进行的,请求和响应都是什么样的,清楚这些之后再进行下一步的操作。
步骤1:新建工程interfaceFramework_practice1,在工程下新建包testScripts用于存放测试脚本文件,在该包下新建testScript.py用户写请求代码
按照接口文档的描述,下面的接口实现了用户的注册、登录、写博客、修改、删除博客等功能,先把每一个接口用代码实现一下。
接口说明:
接口返回code说明:
‘00‘ : 成功
‘01‘:用户已存在
‘02‘:参数不合法
‘03‘:参数错误(1、用户信息错误 2、参数错误,数据库中不存在相应数据)
‘999‘:未知错误,看后台日志
1、用户注册
参数规则说明:
username:
1、必须字母和数字组成
2、长度2~20位
3、字母不区分大小写
password:
1、长度8~20位
2、必须含有字母和数字
email:
标准的email规则
请求的url: http://39.106.41.29:8080/register/
Json串格式参数,请求示例:
{"username": "xufengchai6", "password": "xufengchai121", "email": "[email protected]"}
响应示例:
{"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":"[email protected]"}
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:Python27python.exe D:/test/interfaceFramework_practice1/testScripts/testScript.py
register------
data before json.dumps: {‘username‘: ‘xufengchai6‘, ‘password‘: ‘xufengchai121‘, ‘email‘: ‘[email protected]‘}
data after json.dumps: {"username": "xufengchai6", "password": "xufengchai121", "email": "[email protected]"}
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用于后续处理博文的用户标识
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:Python27python.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:Python27python.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:Python27python.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:Python27python.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:Python27python.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:Python27python.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:Python27python.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": "[email protected]"}
响应示例:
{"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":"[email protected]"}
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":"[email protected]"}‘)
print response.text
结果:ok
C:Python27python.exe D:/test/interfaceFramework_practice1/util/httpClient.py
{"username": "xufengchai6", "code": "01"}
Process finished with exit code 0
在工程下新建testData目录,存放数据文件
inter_test_data.xlsx
这个数据文件可以说是本次接口框架的核心,文件中从每个测试用例sheet都代表一个接口,用例中设计了请求数据的格式、请求依赖数据的格式、检查点、是否需要执行、执行结果、错误信息、响应数据、响应状态码等。
该文件的结构设计直接决定了框架的逻辑设计,程序首先会遍历API sheet中的每一行,区分出需要执行的接口用例,然后到对应的接口用例sheet中读取请求数据,发送http请求,对响应做断言和存储并写入结果,之后再进行下一个接口的处理;其中在处理当前接口用例时会有依赖数据(依赖于上一个接口的请求或响应)的处理,文件中会设置所需依赖数据的格式(模板)和请求数据的格式,程序根据请求数据、依赖数据列存储的格式获取到实际用于请求的数据,然后进行发送请求和后续的处理,如何做依赖数据的处理和存储数据的处理是该框架的难点。
下面就一点一点写主程序,看看需要做哪些处理,首先要读取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:Python27python.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‘:
#获取需要执行的接口所在的行对象
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:Python27python.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
可以看到在读取需要执行的行中每一列的内容时,用的索引号都是数字,这个不用说,肯定是要在公共变量中存一下的。
在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表,准备执行测试用例
caseSheetObj=pe.getSheetByName(apiCaseSheetName)#获取用例sheet对象
caseExecuteCol=pe.getSingleColumn(caseSheetObj,CASE_ifExecute)#获取用例sheet对象中需要执行的列
#遍历需要执行的列
for c_idx,c_cell in enumerate(caseExecuteCol[1:],2):#标题行忽略,c_idx从2开始
if c_cell.value == ‘y‘:
#说明case行需要执行
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列有值的话,需要获取依赖数据
#发送接口数据之前,先做依赖数据的处理
写到这儿让我们来分析一下这个框架的结构和逻辑,它是如何对每个接口进行测试和断言的?这个问题想明白了,这个框架的核心就确定了。
先看下文档中接口的信息:
在注册接口中,请求数据RequestData直接给出了,那么把这列数据取出来,直接发送请求就可以了,然后把结果写在responseData列,注册接口响应参数有code和userid, userid是一个主键,唯一标识一个用户,在checkPoint列设置检查点,和响应code做对比,如果匹配00,就说明注册接口请求成功了,把Result列写入pass。
因为请求数据直接给出了,不需要依赖别的数据,那RelyData列置空,然后有个ResponseCode列需要写一下请求的状态码,比如返回200,就写200,然后看DataStore列,这一列是用来存储接口请求的信息的,可以写请求的参数信息,也可以写响应的参数信息,这个存储数据是干啥的呢,它是用来为其他接口请求做准备数据的;
比如登录接口,在登录之前,需要获取用户的用户名和密码,那它就需要从注册接口的信息来获取,可以在注册接口的DataStore列把用户名和密码信息直接写进去,如username:xiaxiaoxu,password:ksdfjlks,然后再运行登录接口请求时,过来把数据取出来,直接发送请求就行了,登录接口返回的参数有token和userid,这个token是查询博文接口用的;
接下来我们再把各个接口的请求参数和响应参数列出来,然后来看下下游接口的请求数据是如何依赖上游接口的数据的。
注册接口:
请求:
{"username": "xufengchai6", "password": "xufengchai121", "email": "[email protected]"}
响应:
{"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可以依赖于查询用户博文接口的响应数据,也可以依赖于修改博文的请求数据,但是修改博文接口不一定会运行,依赖于查询用户博文接口会稳妥一些
响应:
{"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"}]}
通过上边各个接口的数据依赖关系,可以看出某个接口在请求的之前,要先根据依赖关系到某个上游接口的请求或者响应数据中获取需要的数据,那么怎么去把这个数据获取到呢?以什么规则去获取呢?把这两个个问题解决了,我认为这个框架就成功了一半了!
为啥呢,因为我一半的时间都用来思考这两个问题了,虽然事先已经知道了答案,但是为了透彻的理解其中的原理,花了很长时间来推理这个答案的合理性和必然性~~
对于这种框架的原理,我总是尝试着把所有的细节都揉碎了来重新梳理,推理出每一个步骤的合理性,这样会理解的更深一些。
初步的思路是每个接口在运行的时候把请求数据和响应数据都写到文件里,然后下一个接口在访问的时候去依赖接口中读取请求数据或者响应数据,然后再把请求和响应数据写到自己的sheet表中,以此类推,接着考虑一下实现的细节,这个框架要兼顾多个接口的运行,每个接口的请求数据、存储数据的方法需要用封装的函数来进行处理,这就需要把这些接口的数据信息的获取抽象出一个公用的方法,这个方法可以实现所有接口的数据处理,比如某个接口在获取请求数据时,要先根据接口的请求参数设置一个依赖规则,指明每个参数需要到哪个接口的哪个用例的请求数据或者响应数据中,读取哪个参数的值,每个参数可能需要到不同的接口中获取数据,这个依赖规则需要给出具体的接口名、用例号(行号)、数据类型是请求的还是响应的,然后根据数据类型到不同的列号取值,取的时候,先找到单元格,把内容读出来,转成字典的格式,然后找所需的键值对,有的接口字典深度不止一层(如查询接口),那就要再做一层处理,获取完请求数据信息,就可以发送请求了,之后再把响应数据写到文件中,后续接口可能会用到。
步骤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:Python27python.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
这种获取请求数据方法的思路是,在每个接口中把请求的数据设置一个依赖的规则,用来指明所需的参数来自哪个接口的请求数据还是响应数据,然后程序根据这个依赖规则,去所依赖的地方获取数据。
例如
relyRule={"articleId":"searchUserBlog->1->response->[‘data‘][0]","token":"userLogin->1->response","content": "xiaxiaoxu"},
这个依赖规则是个json串,用json编辑器可以看到它的结构:
可以看到它有三个兄弟节点,代表该接口需要三个请求参数,每个兄弟节点下边是这个参数所依赖的规则,比如"articleId":"searchUserBlog->1->response->[‘data‘][0]",表示"articleId"这个参数依赖的数据是searchUserBlog接口的数据,具体是在searchUserBlog接口的第一个用例的响应数据中的[‘data’]对应的数据中的第1个articleId字段的值,其所依赖的接口数据存储的格式也是json串的形式,可以转成python的字典结构,这样依赖规则的每一层数据都可以用作为字典的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}
需要注意的是,在每个接口获取请求数据时,它所依赖的接口的数据要事先存在,否则就取不到数据了,所以,在处理完每个接口的请求后,需要把请求数据和响应数据写入文件,以备后续接口使用。
下一步实现写入文件的方法
步骤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)
#写校验结果状态列及错误信息列
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表,准备执行测试用例
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:
# 发送接口请求之前,先获取请求数据
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:Python27python.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":"[email protected]"}
type(contentStr): <type ‘unicode‘>
relyContent: {u‘username‘: u‘srsdcx01‘, u‘password‘: u‘wcx123wac1‘, u‘email‘: u‘[email protected]‘}
requestData-1: {‘username‘: u‘srsdcx01‘}
key:value==> password : userRegister->1->request
len(rList): 3
contentStr: {"username":"srsdcx01","password":"wcx123wac1","email":"[email protected]"}
type(contentStr): <type ‘unicode‘>
relyContent: {u‘username‘: u‘srsdcx01‘, u‘password‘: u‘wcx123wac1‘, u‘email‘: u‘[email protected]‘}
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":"[email protected]"}
type(contentStr): <type ‘unicode‘>
relyContent: {u‘username‘: u‘wcd23x‘, u‘password‘: u‘wcx123wac‘, u‘email‘: u‘[email protected]‘}
requestData-1: {‘username‘: u‘wcd23x‘}
key:value==> password : userRegister->2->request
len(rList): 3
contentStr: {"username":"wcd23x","password":"wcx123wac","email":"[email protected]"}
type(contentStr): <type ‘unicode‘>
relyContent: {u‘username‘: u‘wcd23x‘, u‘password‘: u‘wcx123wac‘, u‘email‘: u‘[email protected]‘}
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
文件中的请求数据已经写进去了,先忽略响应数据
发现忘了处理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: est_pythoninterfaceFramework>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:Python27python.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":"[email protected]"}
type(contentStr): <type ‘unicode‘>
relyContent: {u‘username‘: u‘srsdcx01‘, u‘password‘: u‘wcx123wac1‘, u‘email‘: u‘[email protected]‘}
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请求的方式发送给服务器就完成了接口的请求过程,下面在主程序中加入发送请求和写入结果的处理
步骤 6:处理发送请求和写入结果
在主程序中添加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表,准备执行测试用例
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:
# 发送接口请求之前,先获取请求数据
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: est_pythoninterfaceFramework>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: est_pythoninterfaceFramework>python testScript.py
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
apiTestCaseFileName: register
relyRule: None
requestData without relyRule: {"username":"xufengchai6","password":"xufengchai121","email":"[email protected]"} <type ‘unicode‘>
requestMethod, requestUrl, paramsType, requestData:
post http://39.106.41.29:8080/register/ form {"username":"xufengchai6","password":"xufengchai121","email":"[email protected]"}
#############response.text##############: {"code": "00", "userid": 17}
responseData: {"code": "00", "userid": 17}
requestData-4: {"username":"xufengchai6","password":"xufengchai121","email":"[email protected]"}
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":"[email protected]"}
type(contentStr): <type ‘unicode‘>
relyContent: {u‘username‘: u‘xufengchai6‘, u‘password‘: u‘xufengchai121‘, u‘email‘: u‘[email protected]‘}
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":"[email protected]"}
type(contentStr): <type ‘unicode‘>
relyContent: {u‘username‘: u‘xufengchai6‘, u‘password‘: u‘xufengchai121‘, u‘email‘: u‘[email protected]‘}
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
文件截图:
至此,实现了获取请求数据,发送请求,把请求数据和响应数据写入文件
下一步,处理接口结果的校验,判断接口返回数据是否正确
步骤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:Python27python.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表,准备执行测试用例
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:
# 发送接口请求之前,先获取请求数据
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 "接口请求异常,状态码为:",response.status_code
else:
print "接口用例被忽略执行"
else:
print "API测试被忽略"
if __name__ == "__main__":
testInterface()
结果:ok
C:Python27python.exe D:/test/interfaceFramework_practice1/testScripts/testScript.py
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
apiTestCaseFileName: register
relyRule: None
requestData without relyRule: {"username":"xufengchai6","password":"xufengchai121","email":"[email protected]"} <type ‘unicode‘>
requestMethod, requestUrl, paramsType, requestData:
post http://39.106.41.29:8080/register/ form {"username":"xufengchai6","password":"xufengchai121","email":"[email protected]"}
#############response.text##############: {"username": "xufengchai6", "code": "01"}
responseData-1,type(responsedata-1): {"username": "xufengchai6", "code": "01"} <type ‘unicode‘>
requestData-4: {"username":"xufengchai6","password":"xufengchai121","email":"[email protected]"}
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":"[email protected]"}
type(contentStr): <type ‘unicode‘>
relyContent: {u‘username‘: u‘xufengchai6‘, u‘password‘: u‘xufengchai121‘, u‘email‘: u‘[email protected]‘}
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":"[email protected]"}
type(contentStr): <type ‘unicode‘>
relyContent: {u‘username‘: u‘xufengchai6‘, u‘password‘: u‘xufengchai121‘, u‘email‘: u‘[email protected]‘}
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列,所以删掉了,之后换种思路时会用到,到时再加上
以上是关于练习搭建接口自动化测试框架详细过程的主要内容,如果未能解决你的问题,请参考以下文章
API接口自动化测试框架搭建(十九)-日志模块封装(logging模块)
API接口自动化测试框架搭建-接口抓包工具fiddler安装配置及使用