工作中,或者面试中,人家会问有没有什么优势?
你可以说我不光会写接口脚本,还能对接口脚本的结构进行了优化。
接口无非就是输入参数、发送请求、对响应结果进行比对,这些过程 都是一样的。如果不做一个通用的方法。10个接口要写10个方法类,100个更多,那如果 我有一个通用的方法,我只需要做不同的参数就可以了。这样我们脚本的量是最少的。但是所能实现的内容是非常多的。也就是同样的工作内容,但是有不同的工作效率,而且执行起来的速度也会更快一些,因为我们只需要输入数据,代码不需要进行修改,维护成本也会更低一些。
1、接口脚本的优化
1.1 接口脚本优化的价值
1、最大程度上提高了测试脚本的复用性,降低了测试脚本的维护成本
2、只需要不断的追加或替换相关的测试数据即可
3、方便后续接口测试工作的扩展以及测试执行
1.2 如何进行接口测试脚本结构优化
1、优化测试脚本类的设计,对应的接口测试方法需要传入参数。接口访问地址,接口参数(字典数据),接口预期返回结果,接口名称
2、在进行类的实例化的时候,再依据接口测试说明传入相关的参数值
如何进行脚本结构优化呢?
1.3 适用范围
1、适合于接口测试不需要返回值,也不需要特殊参数时
2、接口请求方式是一致的
2、 V1.0版本 基础版本五个类
定义一个登录类,定义五个方法。
# 针对多个接口进行联调测试,接口内容如下:
# 1、用户注册接口
# 2、用户登录接口
# 3、忘记密码接口
# 4、提交密保问题答案
# 5、回答完密保问题后修改密码接口
import requests
# 定义一个接口联调的测试类
class workflow_forgetpassword_test():
# 用户注册接口
def yhzc_test(self):
url="http://localhost:8080/jwshoplogin/user/register.do"
# 正确的用户注册数据
userinfo={"username":"张海1",
"password":"123456",
"email":"1234561@qq.com",
"phone":"13311095555",
"question":"最喜欢的水果",
"answer":"苹果"}
# 发送注册请求,并获取响应
response=requests.post(url,data=userinfo).text
print(response)
r=response.find("注册成功")
if r>0:
print("用户注册接口测试通过")
else:
print("用户注册接口测试失败")
# 2、用户登录接口
def yhdl_test(self):
url="http://localhost:8080/jwshoplogin/user/login.do"
# 正确的用户登录数据
userinfo={"username":"张海1",
"password":"123456"}
# 发送登录请求,并获取响应
response=requests.post(url,data=userinfo).text
print(response)
r=response.find("登录成功")
if r>0:
print("用户登录接口测试通过")
else:
print("用户登录接口测试失败")
# 3、忘记密码接口
def wjmi_test(self):
url="http://localhost:8080/jwshoplogin/user/forget_get_question.do"
# 正确的用户忘记密码数据
userinfo={"username":"张海1"}
# 发送用户忘记密码请求,并获取响应
response=requests.post(url,data=userinfo).text
print(response)
r=response.find("最喜欢的水果")
if r>0:
print("用户忘记密码接口测试通过")
else:
print("用户忘记密码接口测试失败")
# 4、提交密保问题答案
def tjmbwtda_test(self):
url="http://localhost:8080/jwshoplogin/user/forget_check_answer.do"
# 提交密保答案
userinfo={"username":"张海1",
"question":"最喜欢的水果",
"answer":"苹果"}
# 发送提交问题答案接口请求,并获取响应
response=requests.post(url,data=userinfo).text
print(response)
# 1、字符串类型的返回结果,转化为字典类型
dic={}
dic=eval(response)
token=dic["data"]
print(token)
# r=response.find("data")
r = response.find(token)
if r>0:
print("提交问题答案接口请求接口测试通过")
else:
print("提交问题答案接口请求接口测试失败")
# 返回获取到的token
return token
# 5、回答完密保问题后修改密码接口
def hdwtxgmm_test(self,token):
url="http://localhost:8080/jwshoplogin/user/forget_reset_password.do"
# 提交密保答案
print("传入的token",token)
userinfo={"username":"张海1",
"passwordNew":"123456",
"forgetToken":token}
# 发送提交问题答案接口请求,并获取响应
response=requests.post(url,data=userinfo).text
print(response)
r = response.find("修改密码成功")
if r>0:
print("提交问题答案接口请求接口测试通过")
else:
print("提交问题答案接口请求接口测试失败")
# 返回获取到的token
if __name__ == '__main__':
workflowobj=workflow_forgetpassword_test()
# 1、用户注册接口
workflowobj.yhzc_test()
# 2、用户登录接口
workflowobj.yhdl_test()
# 3、忘记密码接口
workflowobj.wjmi_test()
# 4、提交密保问题答案
token=workflowobj.tjmbwtda_test()
# print("返回的token",token)
# 5、回答完密保问题后修改密码接口
workflowobj.hdwtxgmm_test(token)
# 2、用户登录接口
workflowobj.yhdl_test()
3、 V2.0版本 方法的结构优化三各类
根据脚本的适用范围,可以选择优化。
#对多个接口组成的联调测试的脚本 进行结构优化
# 1、用户注册
# 2、用户登录
# 3、忘记密码
# 4、提交密保问题答案
# 5、回答完密保问题后修改密码
这个里面,用户注册、用户登录、忘记密码可以优化成一个接口联调的测试类workflow_forgetpassword_v2,需要从main函数中传入url,userinfo,expresult的参数。4和5需要传递token,因此不能和123写在一起。
# 对多个接口组成的联调测试的脚本进行结构优化V2
# 1、用户注册接口
# 2、用户登录接口
# 3、忘记密码接口
# 4、提交密保问题答案
# 5、回答完密保问题后修改密码接口
import requests
# 定义一个接口联调的测试类
class workflow_forgetpassword_v2_test():
# 用户注册接口
def userinterface_test(self,url,userinfo,expresult,interfacename):
# 发送注册请求,并获取响应
response=requests.post(url,data=userinfo).text
print(response)
r=response.find(expresult)
if r>0:
print(interfacename,"接口测试通过")
else:
print(interfacename,"接口测试失败")
if __name__ == '__main__':
##############注册接口测试数据及调用####################################
url = "http://localhost:8080/jwshoplogin/user/register.do"
# 正确的用户注册数据
userinfo = {"username": "张海2",
"password": "123456",
"email": "12345612@qq.com",
"phone": "13311095555",
"question": "最喜欢的水果",
"answer": "苹果"}
expresult="注册成功"
interfacename="用户注册接口"
workflowobj2=workflow_forgetpassword_v2_test()
workflowobj2.userinterface_test(url,userinfo,expresult,interfacename)
#################登录接口测试数据及调用#########################################
url = "http://localhost:8080/jwshoplogin/user/login.do"
# 正确的用户登录数据
userinfo = {"username": "张海2",
"password": "123456"}
expresult = "登录成功"
interfacename = "用户登录接口"
workflowobj2.userinterface_test(url, userinfo, expresult,interfacename)
4、V3.0 版本,在不同的python文件中进行接口模板类的实例化和调用
在不同的python文件中进行接口模板类的实例化和调用,新建一个python文件,把V2版本方法导入进来,可以在本版本调用
适合场所:多个接口测试开发工程师,同时编写不同的接口测试脚本,进行接口测试的执行
步骤:
1、创建一个新的python文件
2、在文件头部引入接口测试模板类所在文件
3、直接写main函数,进行类的实例化
4、传入相关的接口参数,进行接口测试方法的调用
# 在不同的文件中,调用通用接口测试脚本V3
import requests
from interfacetest.workflow_forgetpassword_v2 import workflow_forgetpassword_v2_test
if __name__ == '__main__':
wjmaObj=workflow_forgetpassword_v2_test()
# 定义接口的URL访问地址
url="http://localhost:8080/jwshoplogin/user/forget_get_question.do"
# 定义接口测试参数
userinfo={"username":"张明"}
# 定义接口预期返回值
expresult="最喜欢的书"
# 定义接口的名称
interfacename="忘记密码接口"
# 调用对应的接口测试方法
wjmaObj.userinterface_test(url,userinfo,expresult,interfacename)
5、V4.0 脚本参数化
在上面的代码中,测试的参数始终在代码行间,因此修改起来比较麻烦。因此可以进一步优化,把相关的接口测试参数放入csv文件中。通过程序把相关的参数读取出来。传入接口测试脚本中
5.1 V4.1版本 解决相同参数的读取问题
首先要解决相同参数的读取问题,我们发现方法中需要传入的参数,都有url,expresult,interfacename,因此可以将他们放一起传入进去。
# v4.1: 共同的接口数据进行读取和传递
import csv
# 读取相关的接口测试文件
file=open("test1.csv","r")
table=csv.reader(file)
userinfo={}
for row in table:
#逐行读取相关内容,并将其设置为相关的参数
url=row[1]
expresult=row[3]
interfacename=row[5]
print("url=",url," ","expresult=",expresult," ","interfacename=",interfacename)
输出结果:
"D:\Program Files\python\python.exe" D:/python/interface/interfacetest/test.py
url= http://localhost:8080/jwshoplogin/user/register.do expresult= 注册成功 interfacename= 用户注册接口
url= http://localhost:8080/jwshoplogin/user/login.do expresult= 登录成功 interfacename= 用户登录接口
url= http://localhost:8080/jwshoplogin/user/check_vaild.do expresult= 校验成功 interfacename= 检测用户名或者邮件是否有效
url= http://localhost:8080/jwshoplogin/user/forget_get_question.do expresult= 最喜欢的水果 interfacename= 忘记密码提示密保接口
Process finished with exit code 0
5.2 V4.1 解决参数个数不同的读取问题
我们可以看到,在发送的数据里,有的参数比较多,有的少。该怎么做呢。
1、找到参数的规律
共同的参数:URL:接口访问地址、expresult:接口响应预期结果、interfacename:接口名称
个性的参数:接口测试数据不同。
首先,将人工测试数据的个数,放到测试数据模板中。
分析从7到18 列,找到循环规律,初始值,终止值,每次变化几个
接着,存放入字典中,字典名[key]=value,userinfo[row[i]]=row[i+1]
一次循环结束后,要把字典数据清空,字典名={ }
价值:以后的接口测试,只需要维护接口测试数据的文档
不需要维护任何的代码
# # v4.2: 共同的接口数据进行读取和传递
import csv
# 读取相关的接口测试文件
file = open("test1.csv", "r")
table = csv.reader(file)
userinfo = {}
for row in table:
j=int(row[6])
for i in range(7,2*j+7,2):
userinfo[row[i]]=row[i+1]
print(userinfo)
userinfo={}
输出结果:
"D:\Program Files\python\python.exe" D:/python/interface/interfacetest/test.py
{'username': '', 'password': '123456', 'email': 'lihui@13.com', 'phone': '13859645626', 'question': '最喜欢的水果', 'answer': '苹果'}
{'username': '张海', 'password': '123456'}
{'str': '李慧3', 'type': 'username'}
{'username': '李慧2'}
5.3 V4.3 版本
# 使用参数化技术进行多个接口联调的测试脚本的优化V4.3
import requests
import csv
# 定义一个接口联调的测试类
class workflow_forgetpassword_v4_test():
# 用户注册接口
def userinterface_test(self,url,userinfo,expresult,interfacename):
# 发送注册请求,并获取响应
response=requests.post(url,data=userinfo).text
print(response)
r=response.find(expresult)
if r>0:
print(interfacename,"接口测试通过")
else:
print(interfacename,"接口测试失败")
if __name__ == '__main__':
workflowobj=workflow_forgetpassword_v4_test()
file=open("test1.csv","r")
table=csv.reader(file)
userinfo = {}
for row in table:
#逐行读取相关内容,并将其设置为相关的参数
url=row[1]
expresult=row[3]
interfacename=row[5]
print("url=", url, " ", "expresult=", expresult, " ", "interfacename=", interfacename)
# 读取接口测试数据
userinfo = {}
j=int(row[6])
for i in range(7,j*2+7,2):
userinfo[row[i]]=row[i+1]
print(userinfo)
workflowobj.userinterface_test(url,userinfo,expresult,interfacename)
输出结果为:
"D:\Program Files\python\python.exe" D:/python/interface/interfacetest/workflow_test_v4.py
url= http://localhost:8080/jwshoplogin/user/register.do expresult= 注册成功 interfacename= 用户注册接口
{'username': '', 'password': '123456', 'email': 'lihui@13.com', 'phone': '13859645626', 'question': '最喜欢的水果', 'answer': '苹果'}
{"status":1,"msg":"用户名已经存在"}
用户注册接口 接口测试失败
url= http://localhost:8080/jwshoplogin/user/login.do expresult= 登录成功 interfacename= 用户登录接口
{'username': '张海', 'password': '123456'}
{"status":0,"msg":"登录成功","data":{"id":25,"username":"张海","password":null,"email":"123456@qq.com","phone":"13311095555","question":"最喜欢的水果","answer":"苹果","role":0,"createTime":1718700342000,"updateTime":1718710506000}}
用户登录接口 接口测试通过
url= http://localhost:8080/jwshoplogin/user/check_vaild.do expresult= 校验成功 interfacename= 检测用户名或者邮件是否有效
{'str': '李慧3', 'type': 'username'}
{"status":0,"msg":"校验成功"}
检测用户名或者邮件是否有效 接口测试通过
url= http://localhost:8080/jwshoplogin/user/forget_get_question.do expresult= 最喜欢的水果 interfacename= 忘记密码提示密保接口
{'username': '李慧2'}
{"status":0,"data":"最喜欢的水果"}
忘记密码提示密保接口 接口测试通过
Process finished with exit code 0
6、V5.0 编写接口测试报告
这个版本需要解决的问题是需要把接口实际响应结果以及测试结论存入测试报告
测试报告设计:接口名称、接口实际返回值、接口测试结论
使用字典数据进行测试结论以及接口实际返回值接收,如resultdata={"实际返回结果":response,"测试结论":"测试通过"}
将字典数据的内容写入测试报告,每完成一组测试,写入一条结论。
6.1 V5.1 定义一个接口联调的测试类,测试报告在main中写。
以登录接口为例,编写测试报告。
# 定义一个接口联调的测试类,测试报告在main中写。
class workflow_forgetpassword_v5_test():
# 用户登录接口
def userinterface_test(self,url,userinfo,expresult,interfacename):
# 定义字典数据,存储实际接口响应结果和测试结论
resultdate={}
# 发送登录请求,并获取响应
response=requests.post(url,data=userinfo).text
print(response)
resultdate["接口实际返回值"] = str(response)
r=response.find(expresult)
if r>0:
print(interfacename,"接口测试通过")
resultdate["测试结论"]="测试通过"
else:
print(interfacename,"接口测试失败")
resultdate["测试结论"] = "测试失败"
print(resultdate)
return resultdate
# 把相关的测试结论写入测试报告
def result_report(self,reportfilename):
file=open(reportfilename,'a')
for key,value in resultdate.items():
file.write(key+","+value+",")
file.write("\n")
file.close()
if __name__ == '__main__':
file2 = open("testresult2.csv", "w")
resultdata={}
workflowobj=workflow_forgetpassword_v5_test()
url = "http://localhost:8080/jwshoplogin/user/login.do"
# 正确的用户登录数据
userinfo = {"username": "张海2",
"password": "123456"}
expresult = "登录成功"
interfacename = "用户登录接口"
resultdate = workflowobj.userinterface_test(url, userinfo, expresult, interfacename)
for key,value in resultdate.items():
file2.write(key+","+value+",")
file2.close()
测试结论:
"D:\Program Files\python\python.exe" D:/python/interface/interfacetest/workflow_test_v5.py
{"status":0,"msg":"登录成功","data":{"id":27,"username":"张海2","password":null,"email":"12345612@qq.com","phone":"13311095555","question":"最喜欢的水果","answer":"苹果","role":0,"createTime":1718772713000,"updateTime":1718772713000}}
用户登录接口 接口测试通过
{'接口实际返回值': '{"status":0,"msg":"登录成功","data":{"id":27,"username":"张海2","password":null,"email":"12345612@qq.com","phone":"13311095555","question":"最喜欢的水果","answer":"苹果","role":0,"createTime":1718772713000,"updateTime":1718772713000}}', '测试结论': '测试通过'}
Process finished with exit code 0
最后CSV中测试是通过的
6.2 V5.2 定义一个接口联调的测试类,测试结论写文件中,a 追加写,单独写一个方法
# 定义一个接口联调的测试类,测试结论写文件中,a 追加写,单独写一个方法。
class workflow_forgetpassword_v5_test():
# 用户登录接口
def userinterface_test(self,url,userinfo,expresult,interfacename):
# 定义字典数据,存储实际接口响应结果和测试结论
resultdate={}
# 发送注册请求,并获取响应
response=requests.post(url,data=userinfo).text
print(response)
resultdate["接口实际返回值"] = str(response)
r=response.find(expresult)
if r>0:
print(interfacename,"接口测试通过")
resultdate["测试结论"]="测试通过"
else:
print(interfacename,"接口测试失败")
resultdate["测试结论"] = "测试失败"
print(resultdate)
return resultdate
# 把相关的测试结论写入测试报告
def result_report(self,reportfilename,resultdate):
file=open(reportfilename,'a')
for key,value in resultdate.items():
file.write(key+","+value+",")
file.write("\n")
file.close()
if __name__ == '__main__':
# file2 = open("testresult2.csv", "a")
resultdata={}
workflowobj=workflow_forgetpassword_v5_test()
url = "http://localhost:8080/jwshoplogin/user/login.do"
# 正确的用户登录数据
userinfo = {"username": "张海2",
"password": "123456"}
expresult = "登录成功"
interfacename = "用户登录接口"
resultdate = workflowobj.userinterface_test(url, userinfo, expresult, interfacename)
workflowobj.result_report("testresult3.csv",resultdate)
输出结果:
{"status":0,"msg":"登录成功","data":{"id":27,"username":"张海2","password":null,"email":"12345612@qq.com","phone":"13311095555","question":"最喜欢的水果","answer":"苹果","role":0,"createTime":1718772713000,"updateTime":1718772713000}}
用户登录接口 接口测试通过
{'接口实际返回值': '{"status":0,"msg":"登录成功","data":{"id":27,"username":"张海2","password":null,"email":"12345612@qq.com","phone":"13311095555","question":"最喜欢的水果","answer":"苹果","role":0,"createTime":1718772713000,"updateTime":1718772713000}}', '测试结论': '测试通过'}
7、V6.0 最终完整版
经过上面的试验,我们需要把功能都合并到一起。
1、一个脚本的程序就可以对应若干条接口测试
2、只需要维护测试数据就可以完成任意一组接口的测试
3、把所有接口测试的结论自动生成测试报告文件
# 把测试脚本结构优化,脚本参数化,以及测试报告所有的技术进行合并V6.0
import csv
import requests
# 定义测试类
class workflow_forgetpassword_v6_test():
# 接口测试通用脚本
def userinterface_test(self, url, userinfo, expresult, interfacename):
# 定义字典数据,存储实际接口响应结果和测试结论
resultdate = {}
# 发送注册请求,并获取响应
response = requests.post(url, data=userinfo).text
print(response)
resultdate["接口实际返回值"] = str(response)
r = response.find(expresult)
if r > 0:
print(interfacename, "接口测试通过")
resultdate["测试结论"] = "测试通过"
else:
print(interfacename, "接口测试失败")
resultdate["测试结论"] = "测试失败"
print(resultdate)
return resultdate
# 把相关的测试结论写入测试报告
def result_report(self,reportfilename,resultdate,interfacename):
file=open(reportfilename,'a')
for key,value in resultdate.items():
file.write(interfacename+","+key+","+value+",")
file.write("\n")
file.close()
if __name__ == '__main__':
workflowobj=workflow_forgetpassword_v6_test()
reportfilename="testresultnew.csv"
file=open("test1.csv","r")
table=csv.reader(file)
for row in table:
#逐行读取相关内容,并将其设置为相关的参数
url=row[1]
expresult=row[3]
interfacename=row[5]
print("url=", url, " ", "expresult=", expresult, " ", "interfacename=", interfacename)
# 读取接口测试数据
userinfo = {}
resultdata={}
j=int(row[6])
for i in range(7,j*2+7,2):
userinfo[row[i]]=row[i+1]
# 调用接口测试方法,传入接口测试数据
resultdata=workflowobj.userinterface_test(url, userinfo, expresult, interfacename)
#调用写入测试报告文件,传入测试结论及实际接口参数
workflowobj.result_report(reportfilename,resultdata,interfacename)
下面是运行结果:
url= http://localhost:8080/jwshoplogin/user/register.do expresult= 注册成功 interfacename= 用户注册接口
{"status":1,"msg":"用户名已经存在"}
用户注册接口 接口测试失败
{'接口实际返回值': '{"status":1,"msg":"用户名已经存在"}', '测试结论': '测试失败'}
url= http://localhost:8080/jwshoplogin/user/login.do expresult= 登录成功 interfacename= 用户登录接口
{"status":0,"msg":"登录成功","data":{"id":25,"username":"张海","password":null,"email":"123456@qq.com","phone":"13311095555","question":"最喜欢的水果","answer":"苹果","role":0,"createTime":1718700342000,"updateTime":1718710506000}}
用户登录接口 接口测试通过
{'接口实际返回值': '{"status":0,"msg":"登录成功","data":{"id":25,"username":"张海","password":null,"email":"123456@qq.com","phone":"13311095555","question":"最喜欢的水果","answer":"苹果","role":0,"createTime":1718700342000,"updateTime":1718710506000}}', '测试结论': '测试通过'}
url= http://localhost:8080/jwshoplogin/user/check_vaild.do expresult= 校验成功 interfacename= 检测用户名或者邮件是否有效
{"status":0,"msg":"校验成功"}
检测用户名或者邮件是否有效 接口测试通过
{'接口实际返回值': '{"status":0,"msg":"校验成功"}', '测试结论': '测试通过'}
url= http://localhost:8080/jwshoplogin/user/forget_get_question.do expresult= 最喜欢的水果 interfacename= 忘记密码提示密保接口
{"status":0,"data":"最喜欢的水果"}
忘记密码提示密保接口 接口测试通过
{'接口实际返回值': '{"status":0,"data":"最喜欢的水果"}', '测试结论': '测试通过'}
Process finished with exit code 0
这样就能实现参数化并能输出测试结论,提高了执行的效率。
遇见问题:写入的返回结果,被逗号分割了起来,没有在一个空格里面。
方法:使用replace函数,将逗号转换为句号。
将
resultdata["接口实际返回值"] = str(response)
替换为
s=str(response)
str1 = s.replace(",", '.')
resultdata["接口实际返回值"]=str1
执行结果:可见问题解决了。
愿每个测试都能顺利转为测试开发,提高职业技能,成为前1%的存在,为社会创造更大的价值,为公司节约更多的成本,为自己和家庭谋求更高的收入,所有人不受职业年龄限制,越老越吃香,直至财富自由;愿测试技术越来越进步,软件质量进一步得到提高,效率提高。愿祖国更加美好,人民更加幸福。多喜乐,常安宁。