为什么要做接口自动化框架

1、业务与配置的分离

2、数据与程序的分离;数据的变更不影响程序

3、有日志功能,实现无人值守

4、自动发送测试报告

5、不懂编程的测试人员也可以进行测试

正常接口测试的流程是什么?

确定接口测试使用的工具----->配置需要的接口参数----->进行测试----->检查测试结果----->生成测试报告

测试的工具:python+requests

接口测试用例:excel

一、接口框架如下:

1、action包:用来存放关键字函数

2、config包:用来存放配置文件

3、TestData:用来存放测试数据,excel表

4、Log包:用来存放日志文件

5、utils包:用来存放公共的类

6、运行主程序interface_auto_test.py

7、Readme.txt:告诉团队组员使用改框架需要注意的地方

二、接口的数据规范设计---Case设计

一个sheet对应数据库里面一张表

APIsheet存放
编号;从1开始
接口的名称(APIName);
请求的url(RequestUrl);
请求的方法(RequestMethod);
传参的方式(paramsType):post/get请求方法不一样
用例说明(APITestCase)
是否执行(Active)部分接口已测通,下次不用测试,直接把这里设置成N,跳过此接口

post与get的区别

查看post详情

post请求参数一般是json串,参数放在from表单里面;参数一般不可见,相对来说安全性高些

查看get详情

get请求参数一般直接放在url里面

2.1注册接口用例

RequestData:请求的数据
(开发制定的传参方式)
RelyData:数据依赖
ResponseCode:响应code
ResponseData:响应数据
DataStore:存储的依赖数据;如果存在数据库里面,在表里增加一个字段用来存依赖的数据
(存储的方式是编写接口自动化的人员来设定的存储方式)
CheckPoint:检查点
Active:是否执行
Status:执行用例的状态,方便查看用例是否执行成功
ErrorInfo:case运行失败,失败的错误信息;eg:是也本身的原因还是case设置失败,还是其他原因

2.2登录接口用例

RequestData:请求的数据
(开发制定的传参方式)
RelyData:数据依赖
(存储的方式是编写接口自动化的人员来设定的存储方式)
ResponseCode:响应code
ResponseData:响应数据
DataStore:存储的依赖数据;如果存在数据库里面,在表里增加一个字段用来存依赖的数据
(存储的方式是编写接口自动化的人员来设定的存储方式)
CheckPoint:检查点
Active:是否执行
Status:执行用例的状态,方便查看用例是否执行成功
ErrorInfo:case运行失败,失败的错误信息;eg:是也本身的原因还是case设置失败,还是其他原因

重点说明下RelyData:数据依赖
采取的是字典:key:value来存储数据格式;
{"request":{"username":"register->1","password":"register->1"},"response":{"code":"register->1"}}

格式化之后:

{
"request":{
"username":"register->1",
"password":"register->1"
},
"response":{
"code":"register->1"
}
}

三、创建utils包:用来存放公共的类
3.1 ParseExcel.py 操作封装excel的类(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) # 设置字体的颜色
# 颜色对应的RGB值
self.RGBDict = {'red': 'FFFF3030', 'green': 'FF008B00'} def loadWorkBook(self, excelPathAndName):
# 将excel文件加载到内存,并获取其workbook对象
try:
self.workbook = openpyxl.load_workbook(excelPathAndName)
except Exception as err:
raise err
self.excelFile = excelPathAndName
return self.workbook def getSheetByName(self, sheetName):
# 根据sheet名获取该sheet对象
try:
# sheet = self.workbook.get_sheet_by_name(sheetName)
sheet = self.workbook[sheetName]
return sheet
except Exception as err:
raise err def getSheetByIndex(self, sheetIndex):
# 根据sheet的索引号获取该sheet对象
try:
# sheetname = self.workbook.get_sheet_names()[sheetIndex]
sheetname = self.workbook.sheetnames[sheetIndex]
except Exception as err:
raise err
# sheet = self.workbook.get_sheet_by_name(sheetname)
sheet = self.workbook[sheetname]
return sheet def getRowsNumber(self, sheet):
# 获取sheet中有数据区域的结束行号
return sheet.max_row def getColsNumber(self, sheet):
# 获取sheet中有数据区域的结束列号
return sheet.max_column def getStartRowNumber(self, sheet):
# 获取sheet中有数据区域的开始的行号
return sheet.min_row def getStartColNumber(self, sheet):
# 获取sheet中有数据区域的开始的列号
return sheet.min_column def getRow(self, sheet, rowNo):
# 获取sheet中某一行,返回的是这一行所有的数据内容组成的tuple,
# 下标从1开始,sheet.rows[1]表示第一行
try:
rows = []
for row in sheet.iter_rows():
rows.append(row)
return rows[rowNo - 1]
except Exception as err:
raise err def getColumn(self, sheet, colNo):
# 获取sheet中某一列,返回的是这一列所有的数据内容组成tuple,
# 下标从1开始,sheet.columns[1]表示第一列
try:
cols = []
for col in sheet.iter_cols():
cols.append(col)
return cols[colNo - 1]
except Exception as err:
raise err def getCellOfValue(self, sheet, coordinate = None,
rowNo = None, colsNo = None):
# 根据单元格所在的位置索引获取该单元格中的值,下标从1开始,
# sheet.cell(row = 1, column = 1).value,
# 表示excel中第一行第一列的值
if coordinate != None:
try:
return sheet[coordinate]
except Exception as err:
raise err
elif coordinate is None and rowNo is not None and \
colsNo is not None:
try:
return sheet.cell(row = rowNo, column = colsNo).value
except Exception as err:
raise err
else:
raise Exception("Insufficient Coordinates of cell !") def getCellOfObject(self, sheet, coordinate = None,
rowNo = None, colsNo = None):
# 获取某个单元格的对象,可以根据单元格所在位置的数字索引,
# 也可以直接根据excel中单元格的编码及坐标
# 如getCellObject(sheet, coordinate = 'A1') or
# getCellObject(sheet, rowNo = 1, colsNo = 2)
if coordinate != None:
try:
# return sheet.cell(coordinate = coordinate)
return sheet[coordinate]
except Exception as err:
raise err
elif coordinate == None and rowNo is not None and \
colsNo is not None:
try:
return sheet.cell(row = rowNo,column = colsNo)
except Exception as err:
raise err
else:
raise Exception("Insufficient Coordinates of cell !") def writeCell(self, sheet, content, coordinate = None,
rowNo = None, colsNo = None, style = None):
#根据单元格在excel中的编码坐标或者数字索引坐标向单元格中写入数据,
# 下标从1开始,参style表示字体的颜色的名字,比如red,green
if coordinate is not None:
try:
# sheet.cell(coordinate = coordinate).value = content
sheet[coordinate] = content
if style is not None:
sheet[coordinate].\
font = Font(color = self.RGBDict[style])
self.workbook.save(self.excelFile)
except Exception as e:
raise e
elif coordinate == None and rowNo is not None and \
colsNo is not None:
try:
sheet.cell(row = rowNo,column = colsNo).value = content
if style:
sheet.cell(row = rowNo,column = colsNo).\
font = Font(color = self.RGBDict[style])
self.workbook.save(self.excelFile)
except Exception as e:
raise e
else:
raise Exception("Insufficient Coordinates of cell !") def writeCellCurrentTime(self, sheet, coordinate = None,
rowNo = None, colsNo = None):
# 写入当前的时间,下标从1开始
now = int(time.time()) #显示为时间戳
timeArray = time.localtime(now)
currentTime = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)
if coordinate is not None:
try:
sheet.cell(coordinate = coordinate).value = currentTime
self.workbook.save(self.excelFile)
except Exception as e:
raise e
elif coordinate == None and rowNo is not None \
and colsNo is not None:
try:
sheet.cell(row = rowNo, column = colsNo
).value = currentTime
self.workbook.save(self.excelFile)
except Exception as e:
raise e
else:
raise Exception("Insufficient Coordinates of cell !") if __name__ == '__main__':
# 测试代码
pe = ParseExcel()
pe.loadWorkBook(r'D:\ProgramSourceCode\Python Source Code\WorkSpace\InterfaceFrame2018\inter_test_data.xlsx')
sheetObj = pe.getSheetByName(u"API")
print("通过名称获取sheet对象的名字:", sheetObj.title)
# print help(sheetObj.rows)
print("通过index序号获取sheet对象的名字:", pe.getSheetByIndex(0).title)
sheet = pe.getSheetByIndex(0)
print(type(sheet))
print(pe.getRowsNumber(sheet)) #获取最大行号
print(pe.getColsNumber(sheet)) #获取最大列号
rows = pe.getRow(sheet, 1) #获取第一行
for i in rows:
print(i.value)
# # 获取第一行第一列单元格内容
# print pe.getCellOfValue(sheet, rowNo = 1, colsNo = 1)
# pe.writeCell(sheet, u'我爱祖国', rowNo = 10, colsNo = 10)
# pe.writeCellCurrentTime(sheet, rowNo = 10, colsNo = 11)

3.2 封装get/post请求(HttpClient.py)

import requests
import json class HttpClient(object):
def __init__(self):
pass def request(self, requestMethod, requestUrl, paramsType,
requestData, headers =None, **kwargs):
if requestMethod == "post":
print("---", requestData, type(requestData))
if paramsType == "form":
response = self.__post(url = requestUrl, data = json.dumps(eval(requestData)),
headers = headers, **kwargs)
return response
elif paramsType == "json":
response = self.__post(url = requestUrl, json = json.dumps(eval(requestData)),
headers = headers, **kwargs)
return response
elif requestMethod == "get":
request_url = requestUrl
if paramsType == "url":
request_url = "%s%s" %(requestUrl, requestData)
response = self.__get(url = request_url, params = requestData, **kwargs)
return response def __post(self, url, data = None, json = None, headers=None,**kwargs):
print("----")
response = requests.post(url=url, data = data, json=json, headers=headers)
return response def __get(self, url, params = None, **kwargs):
response = requests.get(url, params = params, **kwargs)
return response if __name__ == "__main__":
hc = HttpClient()
res = hc.request("get", "http://39.106.41.11:8080/getBlogContent/", "url",'')
print(res.json())

3.3 封装MD5(md5_encrypt)

import hashlib

def md5_encrypt(text):
m5 = hashlib.md5()
m5.update(text.encode("utf-8"))
value = m5.hexdigest()
return value if __name__ == "__main__":
print(md5_encrypt("sfwe"))

3.4 封装Log

import logging
import logging.config
from config.public_data import baseDir # 读取日志配置文件
logging.config.fileConfig(baseDir + "\config\Logger.conf")
# 选择一个日志格式
logger = logging.getLogger("example02")#或者example01 def debug(message):
# 定义dubug级别日志打印方法
logger.debug(message) def info(message):
# 定义info级别日志打印方法
logger.info(message) def warning(message):
# 定义warning级别日志打印方法
logger.warning(message)

3.5 封装发送Email类

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from ProjVar.var import * import os
import smtplib
from email import encoders
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.utils import formataddr def send_mail():
mail_host="smtp.126.com" #设置服务器
mail_user="testman1980" #用户名
mail_pass="wulaoshi1980" #口令
sender = 'testman1980@126.com'
receivers = ['2055739@qq.com',"testman1980@126.com"] # 接收邮件,可设置为你的QQ邮箱或者其他邮箱
# 创建一个带附件的实例
message = MIMEMultipart()
message['From'] = formataddr(["光荣之路吴老师", "testman1980@126.com"])
message['To'] = ','.join(receivers)
subject = '自动化测试执行报告'
message['Subject'] = Header(subject, 'utf-8')
message["Accept-Language"]="zh-CN"
message["Accept-Charset"]="ISO-8859-1,utf-8,gbk"
# 邮件正文内容
message.attach(MIMEText('最新执行的自动化测试报告,请参阅附件内容!', 'plain', 'utf-8')) # 构造附件1,传送测试结果的excel文件
att = MIMEBase('application', 'octet-stream')
att.set_payload(open(ProjDirPath+"\\testdata\\testdata.xlsx", 'rb').read())
att.add_header('Content-Disposition', 'attachment', filename=('gbk', '', "自动化测试报告.xlsx"))
encoders.encode_base64(att)
message.attach(att)
"""
# 构造附件2,传送当前目录下的 runoob.txt 文件
att2 = MIMEText(open('e:\\a.py','rb').read(), 'base64', 'utf-8')
att2["Content-Type"] = 'application/octet-stream'
att2["Content-Disposition"] = 'attachment; filename="a.py"'
message.attach(att2)
"""
try:
smtpObj = smtplib.SMTP(mail_host)
smtpObj.login(mail_user, mail_pass)
smtpObj.sendmail(sender, receivers, message.as_string())
print("邮件发送成功")
except smtplib.SMTPException as e:
print("Error: 无法发送邮件", e) if __name__ == "__main__":
send_mail()

四、 创建config包 用来存放公共的参数、配置文件、长时间不变的变量值
创建public_data.py

import os
# 整个项目的根目录绝对路劲
baseDir = os.path.dirname(os.path.dirname(__file__)) # 获取测试数据文件的绝对路径
file_path = baseDir + "/TestData/inter_test_data.xlsx" API_apiName = 2
API_requestUrl = 3
API_requestMothod = 4
API_paramsType = 5
API_apiTestCaseFileName = 6
API_active = 7 CASE_requestData = 1
CASE_relyData = 2
CASE_responseCode = 3
CASE_responseData = 4
CASE_dataStore = 5
CASE_checkPoint = 6
CASE_active = 7
CASE_status = 8
CASE_errorInfo = 9 # 存储请求参数里面依赖的数据
REQUEST_DATA = {} # 存储响应对象中的依赖数据
RESPONSE_DATA = {} if __name__=="__main__":
print(file_path)
print(baseDir)

五、创建TestData目录,用来存放测试文件
inter_test_data.xlsx

六、创建action包,用来存放关键字函数
6.1 解决数据依赖 (GetRely.py)

from config.public_data import REQUEST_DATA, RESPONSE_DATA
from utils.md5_encrypt import md5_encrypt REQUEST_DATA = {"用户注册":{"":{"username":"zhangsan", "password":"dfsdf23"},
"headers":{"cookie":"asdfwerw"}}}
RESPONSE_DATA = {"用户注册":{"":{"code":""}, "headers":{"age":2342}}} class GetRely(object):
def __init__(self):
pass @classmethod
def get(self, dataSource, relyData, headSource = {}):
print(type(dataSource))
print(dataSource)
data = dataSource.copy()
for key, value in relyData.items():
if key == "request":
#说明应该去REQUEST_DATA中获取
for k, v in value.items():
interfaceName, case_idx = v.split("->")
val = REQUEST_DATA[interfaceName][case_idx][k]
if k == "password":
data[k] = md5_encrypt(val)
else:
data[k] = val
elif key == "response":
# 应该去RESPONSE_DATA中获取
for k, v in value.items():
interfaceName, case_idx = v.split("->")
data[k] = RESPONSE_DATA[interfaceName][case_idx][k]
elif key == "headers":
if headSource:
for key, value in value.items():
if key == "request":
for k, v in value.items():
for i in v:
headSource[i] = REQUEST_DATA[k]["headers"][i]
elif key == "response":
for i, val in value.items():
for j in val:
headSource[j] = RESPONSE_DATA[i]["headers"][j]
return "%s" %data if __name__ == "__main__":
s = {"username": "", "password": "","code":""}
h = {"cookie":"", "age":332}
rely = {"request": {"username": "用户注册->1", "password": "用户注册->1"},
"response":{"code":"用户注册->1"},
"headers":{"request":{"用户注册":["cookie"]},"response":{"用户注册":["age"]}}
}
print(GetRely.get(s, rely, h))

6.2 解决数据存储(RelyDataStore.py)

from config.public_data import RESPONSE_DATA, REQUEST_DATA

class RelyDataStore(object):
def __init__(self):
pass @classmethod
def do(cls, storePoint, apiName, caseId, request_source = {}, response_source = {}, req_headers={}, res_headers = {}):
for key, value in storePoint.items():
if key == "request":
# 说明需要存储的依赖数据来自请求参数,应该将数据存储到REQUEST_DATA
for i in value:
if i in request_source:
val = request_source[i]
if apiName not in REQUEST_DATA:
# 说明存储数据的结构还未生成,需要指明数据存储结构
REQUEST_DATA[apiName]={str(caseId): {i: val}}
else:
#说明存储数据结构中最外层结构已存在
if str(caseId) in REQUEST_DATA[apiName]:
REQUEST_DATA[apiName][str(caseId)][i] = val
else:
# 说明内层结构不完整,需要指明完整的结构
REQUEST_DATA[apiName][str(caseId)] = {i: val}
else:
print("请求参数中不存在字段" + i)
elif key == "response":
#说明需要存储的依赖数据来自接口的响应body,应该将数据存储到RESPONSE_DATA
for j in value:
if j in response_source:
val = response_source[j]
if apiName not in RESPONSE_DATA:
# 说明存储数据的结构还未生成,需要指明数据存储结构
RESPONSE_DATA[apiName]={str(caseId): {j: val}}
else:
#说明存储数据结构中最外层结构已存在
if str(caseId) in RESPONSE_DATA[apiName]:
RESPONSE_DATA[apiName][str(caseId)][j] = val
else:
# 说明内层结构不完整,需要指明完整的结构
RESPONSE_DATA[apiName][str(caseId)] = {j: val}
else:
print("接口的响应body中不存在字段" + j)
elif key == "headers":
for k, v in value.items():
if k == "request":
# 说明需要往REQUEST_DATA变量中写入存储数据
for item in v:
if item in req_headers:
header = req_headers[item]
if "headers" in REQUEST_DATA[apiName]:
REQUEST_DATA[apiName]["headers"][item] = header
else:
REQUEST_DATA[apiName]["headers"] = {item: header}
elif k == "response":
# 说明需要往RESPONSE_DATA变量中写入存储数据
for it in v:
if it in res_headers:
header = res_headers[it]
if "headers" in RESPONSE_DATA[apiName]:
RESPONSE_DATA[apiName]["headers"][it] = header
else:
RESPONSE_DATA[apiName]["headers"] = {item: header}
print(REQUEST_DATA)
print(RESPONSE_DATA) if __name__ == "__main__":
r = {"username": "srwcx01", "password": "wcx123wac1", "email": "wcx@qq.com"}
req_h = {"cookie":"csdfw23"}
res_h = {"age":597232}
s = {"request": ["username", "password"], "response": ["userid"],"headers":{"request":["cookie"],
"response":["age"]}}
res = {"userid": 12, "code": ""}
RelyDataStore.do(s, "register", 1, r, res, req_headers=req_h, res_headers=res_h)
print(REQUEST_DATA)
print(RESPONSE_DATA)

6.3 校验数据结果(CheckResult.py)

import re

class CheckResult(object):
def __init__(self):
pass @classmethod
def check(self, responseObj, checkPoint):
responseBody = responseObj.json()
# responseBody = {"code": "", "userid": 12, "id": "12"}
errorKey = {}
for key, value in checkPoint.items():
if key in responseBody:
if isinstance(value, (str, int)):
# 等值校验
if responseBody[key] != value:
errorKey[key] = responseBody[key]
elif isinstance(value, dict):
sourceData = responseBody[key]
if "value" in value:
# 模糊匹配校验
regStr = value["value"]
rg = re.match(regStr, "%s" %sourceData)
if not rg:
errorKey[key] = sourceData
elif "type" in value:
# 数据类型校验
typeS = value["type"]
if typeS == "N":
# 说明是整形校验
if not isinstance(sourceData, int):
errorKey[key] = sourceData
else:
errorKey[key] = "[%s] not exist" %key
return errorKey if __name__ == "__main__":
r = {"code": "", "userid": 12, "id": 12}
c = {"code": "", "userid": {"type": "N"}, "id": {"value": "\d+"}}
print(CheckResult.check(r, c))

6.4 往excel里面写结果

from config.public_data import *

def write_result(wbObj, sheetObj, responseData, errorKey, rowNum):
try:
# 写响应body
wbObj.writeCell(sheetObj, content="%s" %responseData,
rowNo = rowNum, colsNo=CASE_responseData)
# 写校验结果状态及错误信息
if errorKey:
wbObj.writeCell(sheetObj, content="%s" %errorKey,
rowNo=rowNum, colsNo=CASE_errorInfo)
wbObj.writeCell(sheetObj, content="faild",
rowNo=rowNum, colsNo=CASE_status, style="red")
else:
wbObj.writeCell(sheetObj, content="pass",
rowNo=rowNum, colsNo=CASE_status, style="green")
except Exception as err:
raise err

七、创建Log目录用来存放日志

八、主函数

#encoding=utf-8
import requests
import json
from action.get_rely import GetRely
from config.public_data import *
from utils.ParseExcel import ParseExcel
from utils.HttpClient import HttpClient
from action.data_store import RelyDataStore
from action.check_result import CheckResult
from action.write_result import write_result
from utils.Log import * def main():
parseE = ParseExcel()
parseE.loadWorkBook(file_path)
sheetObj = parseE.getSheetByName("API")
activeList = parseE.getColumn(sheetObj, API_active)
for idx, cell in enumerate(activeList[1:], 2):
if cell.value == "y":
#需要被执行
RowObj = parseE.getRow(sheetObj, idx)
apiName = RowObj[API_apiName -1].value
requestUrl = RowObj[API_requestUrl - 1].value
requestMethod = RowObj[API_requestMothod - 1].value
paramsType = RowObj[API_paramsType - 1].value
apiTestCaseFileName = RowObj[API_apiTestCaseFileName - 1].value # 下一步读取用例sheet表,准备执行测试用例
caseSheetObj = parseE.getSheetByName(apiTestCaseFileName)
caseActiveObj = parseE.getColumn(caseSheetObj, CASE_active)
for c_idx, col in enumerate(caseActiveObj[1:], 2):
if col.value == "y":
#需要执行的用例
caseRowObj = parseE.getRow(caseSheetObj, c_idx)
requestData = caseRowObj[CASE_requestData - 1].value
relyData = caseRowObj[CASE_relyData - 1].value
responseCode = caseRowObj[CASE_responseCode - 1].value
responseData = caseRowObj[CASE_responseData - 1].value
dataStore = caseRowObj[CASE_dataStore -1].value
checkPoint = caseRowObj[CASE_checkPoint - 1].value #发送接口请求之前需要做一下数据依赖的处理
if relyData:
logging.info("处理第%s个接口的第%s条用例的数据依赖!")
requestData = GetRely.get(eval(requestData), eval(relyData))
httpC = HttpClient()
response = httpC.request(requestMethod=requestMethod,
requestData=requestData,
requestUrl=requestUrl,
paramsType=paramsType
)
# 获取到响应结果后,接下来进行数据依赖存储逻辑实现
if response.status_code == 200:
responseData = response.json()
# 进行依赖数据存储
if dataStore:
RelyDataStore.do(eval(dataStore), apiName, c_idx - 1, eval(requestData), responseData)
# 接下来就是校验结果
else:
logging.info("接口【%s】的第【%s】条用例,不需要进行依赖数据存储!" %(apiName, c_idx))
if checkPoint:
errorKey = CheckResult.check(response, eval(checkPoint))
write_result(parseE, caseSheetObj, responseData, errorKey, c_idx)
else:
logging.info("接口【%s】的第【%s】条用例,执行失败,接口协议code非200!" %(apiName, c_idx))
else:
logging.info("第%s个接口的第%s条用例,被忽略执行!" %(idx -1, c_idx-1))
else:
logging.info("第%s行的接口被忽略执行!" %(idx -1)) if __name__=="__main__":
main()

框架待完善~~请各路神仙多多指教~~

python+requests接口自动化框架的更多相关文章

  1. python+request接口自动化框架

    python+request接口自动化框架搭建 1.数据准备2.用python获取Excel文件中测试用例数据3.通过requests测试接口4.根据接口返回的code值和Excel对比 但本章只讲整 ...

  2. python+requests接口自动化测试框架实例详解

    python+requests接口自动化测试框架实例详解   转自https://my.oschina.net/u/3041656/blog/820023 摘要: python + requests实 ...

  3. python+requests接口自动化测试框架实例详解教程

    1.首先,我们先来理一下思路. 正常的接口测试流程是什么? 脑海里的反应是不是这样的: 确定测试接口的工具 —> 配置需要的接口参数 —> 进行测试 —> 检查测试结果(有的需要数据 ...

  4. 【接口自动化】Python+Requests接口自动化测试框架搭建【三】

    经过上两篇文章的讲解,我们已经完成接口自动化的基础框架,现在开始根据实际项目丰满起来. 在PyCharm中新建项目,项目工程结构如下: config:配置文件夹,可以将一些全局变量放于配置文件中,方便 ...

  5. 【接口自动化】Python+Requests接口自动化测试框架搭建【一】

    公司项目启用新框架,前后端分离,所以接口测试成为测试工作中不可缺失的一个环节,现在将从0开始搭建接口自动化测试框架的路程,一步步记录下来. 开发语言我们采用Python+第三方库Requests,测试 ...

  6. python+requests接口自动化完整项目设计源码

    前言 有很多小伙伴吵着要完整的项目源码,完整的项目属于公司内部的代码,这个是没法分享的,违反职业道德了,就算别人分享了,也只适用于本公司内部的业务. 所以用例的代码还是得自己去一个个写,我只能分享项目 ...

  7. python+requests接口自动化完整项目设计源码(一)

    原文地址https://www.cnblogs.com/yoyoketang/tag/python接口自动化/ 原文地址https://www.cnblogs.com/yoyoketang/ 原文地址 ...

  8. 【接口自动化】Python+Requests接口自动化测试框架搭建【二】

    接续前文,在上篇博客中我们编写了demo.py代码,里面代码过多冗余,更新代码: #!/usr/bin/env python # coding=utf-8 import requests class ...

  9. Python+requests接口自动化完整项目框架整理笔记

    前言 通过学习"上海悠悠"博客,自己手动敲了一遍整体的自动化项目搭建,编写用例,打印log日志,生成测试报告,将报告发送至邮箱整体流程跑了一遍,勉强跑通了 一,项目结构 --cas ...

随机推荐

  1. python学习笔记:(三)list(列表)常用的内置方法

    list(列表)包含一些内置的方法,以下为详细介绍: (方法调用:对象.方法(参数)) 1.append() 在列表的末尾添加新的对象 如: lst=[1,2,3] lst.append(4) --- ...

  2. python学习之文件读写操作

    open函数 在使用文件之前,需要先打开,即使用open函数 如: files=open("文件路径","操作方式") 解释如下: (1.files:为文件对象 ...

  3. 如何在linux上部署vue项目

    安装nginx的前奏 安装依赖 yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel 创建一个文件夹 cd /usr/ ...

  4. tensorflow学习之Saver保存读取

    目前不是很懂..但主要意思是tf可以把一开始定义的参数,包括Weights和Biases保存到本地,然后再定义一个变量框架去加载(restore)这个参数,作为变量本身的参数进行后续的训练,具体如下: ...

  5. Mongodb-简单部署

    一.MongoDB是一款NoSql数据库 二.部署单实例MongoDB 1.安装环境: (1)系统:Centos7.2 (2)MongoDB:Percona的MongoDB3.4 2.配置yum源 p ...

  6. java基础知识部分知识点

    1.Java常见的注释有哪些,语法是怎样的? 1)单行注释用//表示,编译器看到//会忽略该行//后的所文本  2)多行注释/* */表示,编译器看到/*时会搜索接下来的*/,忽略掉/* */之间的文 ...

  7. 编写Servlet步骤以及Servlet生命周期是怎样的

    一.编写Servlet步骤 1.继承HttpServlet,HttpServlet在javax-servlet-api依赖下 2.重写doGet()或者doPost()方法 3.在web.xml中注册 ...

  8. Python作图包含type3字体解决方案

    1. 解决方案 matplotlib.rcParams[‘text.usetex’] = True

  9. 最长上升子序列(LIS) Medium2

    JGShining's kingdom consists of 2n(n is no more than 500,000) small cities which are located in two ...

  10. 一条简单的 SQL 查询语句到底经历了什么?

    一.MySQL 基础架构   整体来说 MySQL 主要分为两个部分,一个部分是:Server 层,另一部分是:存储引擎层. 其中 Server 层包括有连接器.查询缓存.分析器.优化器.执行器等,存 ...