python+requests+unittest接口自动化测试框架[之前写的文章,写在博客上,记录下来。]
前言:
接口测试之前用的工具是postman和Jmeter,一般测试工具做接口测试的流程:选择接口测试工具—>配置接口请求和接口参数->参数化->进行测试,检查测试结果。
这次打算用python+requests+unittest来设计接口测试框架,参考以上测试流程,还需要代码做到业务和数据的分离,这样使用起来比较灵活,以下记录过程。
request:用于发送get,post,put等请求
xlrd:操作Excel,提取测试数据
logging:日志记录
json:数据json处理
configparser:读取配置文件
序号 |
目录 |
文件 |
1 |
common目录:存放一些公共的方法 |
公共方法:common.py |
2
|
config目录:config配置文件以及数据库的相关信息,接口的相关信息等 |
日志服务:log.py |
3 |
Data目录: 测试用例的测试数据 |
读取数据:read_excel.py |
4 |
testcase目录:用于存放具体的测试case |
Api接口:testApi.py 读取配置文件:readconfig.py |
2 |
config目录:config配置文件以及数据库的相关信息,接口的相关信息等 |
配置文件:config.conf |
3 |
Data目录: 测试用例的测试数据 |
数据文件:data.xlsx |
4 |
testcase目录:用于存放具体的测试case |
testLoginApi.py |
5 |
run_main:主执行程序 |
run_main.py |
6 |
logs目录:执行生成的日志 |
"执行时才会生成日志目录" |
7 |
repoort目录:存放每次执行过程中的测试结果 |
"执行时才会生成report目录" |
数据包括:Name,url,Data,Method,Code
执行流程:
1、Excel定义URL,Data等列。脚本执行流程如下:
2、使用xlrd工具读取Excel中的信息和配置文件config.conf的初始url,拼接成一个个完整的请求。[或者这里直接用excel读取url也是可以的]
3、接口请求类拿到一个个完整的请求的去执行,这个过程需要记录日志,每一次执行情况都要进行记录,做到有迹可循。
4、使用unittest+htmlTestRunner执行,生成html报告。
数据是放在Excel中的,用xlrd来读取数据,写数据需要用到xluntils,
需要先安装:
pip install xlrd
pip install xluntils
思路:
1使用xlrd方法读取xlsx的文件,然后存入list变量参数中
2执行时调用list变量参数
解决方案:
For语句循环行读取每一列的值
方法:self.getRows()
self.getSheet().cell_value(i, 0)
for i in range(1,self.getRows()):
TestName.append(self.getSheet().cell_value(i, 0))
思路:使用代码生成日志文件
解决方案:
1使用Python代码显式的创建loggers, handlers和formatters并分别调用它们的配置函数
# logging对象,设置从那个等级开始提示
logger = logging.getLogger()
#创建handler
time_handler=logging.handlers.TimedRotatingFileHandler(logfile,'D')
#handler设置日志格式
fmt=logging.Formatter("%(asctime)s - %(name)s -%(module)s- %(levelname)s - %(message)s","%Y-%m-%d %H:%M:%S")
time_handler.setFormatter(fmt)
#添加刚设置的handler
logger.addHandler(time_handler)
2生成日志文件,文件:logs\当前日期\log+时间.log
#日志文件
logfile = os.path.join(log_path,"log%s.log") %time
首先安装第三方模块requests
pip install requests
思路:接口测试的封装(requests api请求)
if (method == "get" or "GET"):
try:
result = requests.get(url, params=data,cookies=cookies)
except Exception as e:
logging.error("发起get请求报错,错误是:", e)
print("发起get请求报错,错误是:", e)
elif (method == "post" or "POST"):
try:
result = requests.post(url, params=data,cookies=cookies)
except Exception as e:
logging.error("发起post请求报错,错误是:", e)
login的接口测试用例
import sys, os
sys.path.append('../') from common.read_excel import readData from common.testApi import testApi from common.readConfig import readConfig
import unittest import json import logging
# 生成日志文件(本程序单独执行时可使用) # import common.log as log # log.logfile()
class testLoginApi(unittest.TestCase): def setUp(self): print('\n')
def test_LoginApi(self): # 测试login的接口 logging.info('------testLoginApi------.')
# 获取当前执行(调用)程序的当前目录,本程序执行,当前目录为D:\python_apitest\src\testcase;runtest.py执行时当前目录为:D:\python_apitest\src root_dir = os.path.abspath('.') if "testcase" in root_dir: data_path = "../data/data.xlsx" configpath="../config/config.conf" else: data_path = "data/data.xlsx" configpath="config/config.conf"
# 获取参数化数据 excel = readData(r'%s' % data_path) # excel = readData(r'D:\python_test\mdp_test3\config\data.xlsx') row = excel.getRows() url = excel.getUrl() method = excel.getMethod() headers = excel.getHeaders() data = excel.getData() exceptcode = excel.getCode() # 参数data里的预期结果
#读取配置文件 #readconfig=readConfig("../config/config.conf") #在当前程序调用时,使用这个 readconfig=readConfig(configpath) #print (readconfig) baseurl=readconfig.get_http("baseurl") port=readconfig.get_http("port") #print (baseurl,port)
# 一行一行参数化数据执行 for i in range(0, row - 1):
if port=="": requesturl=baseurl+url[i] else: requesturl=baseurl+":"+port+url[i] print (requesturl) try: api = testApi() result = api.requestsApid(method[i],requesturl,eval(data[i])) # 调用requestApid的接口 print("请求url%s" % result.url) # 打印请求的url logging.info("请求url:%s" % result.url) apijson = result.json() # 获取请求返回实际结果的json串值 # print (apijson) # print (type(apijson)) logging.info("请求返回值的json串值:%s" % apijson)
# 获取返回实际结果json串值的state值 actualstate = apijson["state"] actualmessage = apijson["message"] except Exception as e: print(e) logging.error(e) # print (actualcode) # print (eval(exceptcode[i])) # print (type(eval(exceptcode[i]))) exceptstate = eval(exceptcode[i])["state"] exceptmessage = eval(exceptcode[i])["message"] # print (actualstate,type(actualstate)) # print (exceptstate,type(exceptstate))
if (actualstate == exceptstate): logging.info('检查结果:testLoginApi True,-实际state:%s,预期state:%s.' % (actualstate, exceptstate)) print('检查结果:testLoginApi True,-实际state:%s,预期state:%s.' % (actualstate, exceptstate)) else: logging.error('检查结果:testLoginApi False,-[实际state:%s,实际message:%s] ,[预期state:%s,预期message:%s].' % ( actualstate, actualmessage, exceptstate, exceptmessage)) print('检查结果:testLoginApi False,-[实际state:%s,实际message:%s] ,[预期state:%s,预期message:%s].' % ( actualstate, actualmessage, exceptstate, exceptmessage)) self.assertEqual(actualstate, exceptstate, "两者的值不相等")
def tearDown(self): pass |
prin
2.8主程序调用
例子1:run_main1.py
使用unittest.defaultTestLoader.discover方法执行测试用例
def runAutomation():
filename = path + r'\report\Report_' + getNowTime() + '.html'
fp = open(filename, 'wb')
runner = HTMLTestRunner(
stream=fp,
title=u'接口自动化测试报告',
description=u'接口自动化测试报告详细的信息'
)
runner.run(suite())
if __name__ == '__main__':
runAutomation()