搭建接口自动化测试框架(文中接口数据来自于光荣之路)

在设计接口测试框架前,先来弄清楚接口测试怎么进行的,请求和响应都是什么样的,清楚这些之后再进行下一步的操作。

步骤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": "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用于后续处理博文的用户标识

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都代表一个接口,用例中设计了请求数据的格式、请求依赖数据的格式、检查点、是否需要执行、执行结果、错误信息、响应数据、响应状态码等。

该文件的结构设计直接决定了框架的逻辑设计,程序首先会遍历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:\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':

#获取需要执行的接口所在的行对象

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

可以看到在读取需要执行的行中每一列的内容时,用的索引号都是数字,这个不用说,肯定是要在公共变量中存一下的。

在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": "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可以依赖于查询用户博文接口的响应数据,也可以依赖于修改博文的请求数据,但是修改博文接口不一定会运行,依赖于查询用户博文接口会稳妥一些

响应:

{"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:\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

这种获取请求数据方法的思路是,在每个接口中把请求的数据设置一个依赖的规则,用来指明所需的参数来自哪个接口的请求数据还是响应数据,然后程序根据这个依赖规则,去所依赖的地方获取数据。

例如

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:\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

文件中的请求数据已经写进去了,先忽略响应数据

发现忘了处理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请求的方式发送给服务器就完成了接口的请求过程,下面在主程序中加入发送请求和写入结果的处理

步骤 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:\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

文件截图:

至此,实现了获取请求数据,发送请求,把请求数据和响应数据写入文件

下一步,处理接口结果的校验,判断接口返回数据是否正确

步骤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表,准备执行测试用例

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:\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

搭建接口自动化测试框架详细过程相关推荐

  1. 基于pytest搭建接口自动化测试框架,提供源码

    基于pytest搭建接口自动化测试框架 框架整体介绍和方法教程 新框架(比这个功能多了很多,用例使用yaml编写) 源码框架结构 xmind项目结构介绍 源码地址 使用教程 1.全局变量设置和使用 2 ...

  2. 如何搭建接口自动化测试框架?

    为什么要做(自动化)接口测试? 1.由于现在各个系统的复杂度不断上升,导致传统的测试方法成本上升且测试效率大幅下降,而接口测试相对于UI测试更加稳定,且相对容易实现自动化持续集成,可以减少人工回归测试 ...

  3. 接口报params province error_Python3+requests搭建接口自动化测试框架

    01 接口自动化的意义(为什么做这个框架?) 新版本上线时之前版本的功能需要进行回归测试,导致大量的重复性手工测试. 引入自动化测试可以使用自动化技术代替部分手工的回归性测试,解放更多人力做其它更有必 ...

  4. 基于Python接口自动化测试框架(初级篇)附源码

    目录 1.引言 1.框架设计思路 2.框架设计思路 3.运行程序 4.源码获取 引言 很多人都知道,目前市场上很多自动化测试工具,比如:Jmeter,Postman,TestLink等,还有一些自动化 ...

  5. Python+unittest+requests 接口自动化测试框架搭建 完整的框架搭建过程 实战

    一.Python+unittest+requests+HTMLTestRunner 完整的接口自动化测试框架搭建_00--框架结构简解 首先配置好开发环境,下载安装Python并下载安装pycharm ...

  6. API接口自动化测试框架搭建(一)-总体需求

    (一)-总体需求 1 实现目的 2 功能需求 3 其他要求 4 适用人员 5 学习周期 6 学习建议 7 内容直达 8 反馈联系 1 实现目的 API接口自动化测试,主要针对http接口协议: 便于回 ...

  7. pytest接口自动化测试框架搭建

    文章目录 一. 背景 二. 基础环境 三. 项目结构 四.框架解析 4.1 接口数据文件处理 4.2 封装测试工具类 4.3 测试用例代码编写 4.4 测试用例运行生成报告 一. 背景 Pytest目 ...

  8. 【Python自动化测试20】接口自动化测试框架模型搭建

    文章目录 一.前言 二.框架搭建流程 2.1 项目创建 2.2 README文件 2.3 .gitignore文件 2.4 什么是测试框架? 2.5 分层设计 2.6 框架搭建 2.6.1 公用目录( ...

  9. 接口自动化测试框架搭建:基于python+requests+pytest+allure实现

    目录 一.接口自动化测试框架需要具备什么功能? 二.接口自动化测试框架目录结构 三.日志监控文件的信息 四.搭建具有企业Logo的定制化报告. 众所周知,目前市面上大部分的企业实施接口自动化最常用的有 ...

  10. 手把手教你搭建java接口自动化测试框架(四):断言、生成测试报告

    手把手教你搭建java接口自动化测试框架(四):断言.生成测试报告 上一集说到post和Get请求,请求后得到的响应(即接口返回值)是我们想要的吗 比如网站上get接口文档说明 : "dat ...

最新文章

  1. 病毒周报(081110至081116)
  2. matlab 层次聚类
  3. 走进Java中的持有对象(容器类)之一 容器分类
  4. 怎么判断一个字符串的最长回文子串是否在头尾_LeetCode 第 131 号问题:分割回文串...
  5. coffeescript html5,HTML5——前端预处理技术(Less、Sass、CoffeeScript)
  6. java nio 缓冲区(一)
  7. Javascript:事件对象—event
  8. 演示6:python音乐下载器
  9. 【大数据处理技术】实验7(推荐林子雨老师的教程)
  10. 如何在Edge中添加兼容性站点?
  11. 周报,当前是第几周 ?
  12. 数数小绵羊(四刷) kkmd66
  13. 此次边路调整系统推荐射手走哪路_此次边路的调整系统会推荐射手走什么路呢...
  14. box-sizing: border-box;box-sizing:content-box;讲解
  15. 大四会计转码 初学c语言的心路历程
  16. 闲鱼卖家待发货在哪看
  17. C语言2进制与10进制转换
  18. Python基金投资回测
  19. IT小唐的python函数库
  20. linux /etc/rc.d/目录及rc.local的详解

热门文章

  1. 中国银行手机银行登入显示服务器,中国银行手机银行登录指南
  2. Xv6 Page Table
  3. 地籍图宗记注记标注实现
  4. Android开发中加载Gif动画图片方法
  5. unity3d大型互动照片墙
  6. acrobat dc mac版_Adobe Acrobat Pro DC mac版-Adobe Acrobat Pro DC for Macv2019.021.20048 免费版__西西软件下载...
  7. 2021五一数学建模B题思路
  8. win10 安装MASM32 遇到的问题DELETE operation of EXE file has failed
  9. NVIDIA Control Panel 闪退(英伟达控制面板闪退)
  10. 物联网LoRa系列-2:LoRa系统架构与协议栈详解