社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python3简易接口自动化测试框架设计与实现(上)

51Testing软件测试网 • 6 年前 • 835 次点击  


目录

 

 1、开发环境

 2、用到的模块

 3、框架设计

 3.1、流程

 3.2、项目结构

 4、日志打印

 5、接口请求类封装

 6、Excel数据读取

 6.1、读取配置文件

 6.2、编写Excel操作类

 7、用例组装

 8、用例运行结果校验

 9、运行用例

 10、小结


1、开发环境

  • 操作系统:Ubuntu18

  • 开发工具:IDEA+PyCharm插件

  • Python版本:3.6


2、用到的模块

  • requests:用于发送请求

  • xlrd:操作Excel,组织测试用例

  • smtplib,email:发送测试报告

  • logging:日志追踪

  • json:数据格式化

  • Django:接口开发

  • configparser:读取配置文件


3、框架设计

  3.1、流程

  接口用例是通过Excel来组织的,定义了URL,Request Body等列。执行流程如下:

  • 使用xlrd工具读取Excel中的信息,拼接成一个个完整的请求。

  • 接口请求类拿到一个个完整的请求的去执行,这个过程需要记录日志,每一次执行情况都要有迹可循。

  • 回填测试结果,发送邮件,归档每次的运行结果。更好一点的做法是把历史运行情况做个报表,更直观。

  优点:

  • 用例通过Excel来组织,不需要编写代码,上手难度小。

  • 在用例个数不是很多的情况,开发速度快。

  缺点:

  • 用例依赖是痛点。

  • 只能支持接口自动化用例。

  • Excel中用例无法预先检查正确性,只有跑一把才能知道。

  • 无法很好地管理大量用例,且不支持团队协同作业,个人用来回归测试或上线后的冒烟测试会是一个不错的选择。

  通过优缺点的对比,可以明显发现这个框架的硬伤其实很多了。所以无论是业界开源的自动化测试框架或企业自研的还没有见过用Excel来组织用例的。值得一提的是个别企业自研的自动化框架非常难用,抑或是把一堆工具简单组合到一起。根本无法提高团队的生产力。不过好的产品也不是一蹴而就的,需要一个持续优化的过程。所以上面用Excel组织用例的框架还是值的玩一玩的,暂且命名为apitest吧。目前比较好的自动化测试框架有unittest,testng,pytest等。

  3.2、项目结构

  testcase:存放测试用例或请求的json文件。

  config:配置文件。

  report:测试报告和日志文件及其归档。

  untils:工具集,send_request用来发送请求,email_tool用来发送邮件,excel_tool用来读取Excel中的数据,check_result用来校验结果,run_main用例执行入口,log_trace用来追踪日志。


4、日志打印


  采用内置logging模块才记录运行日志,设置日志级别。

  log_trace.log:

import  logging

filename = "../report/test_case_run.log"

logging.basicConfig(level=logging.INFO,

format='%(asctime)s %(levelname)s1 %(filename)s [line:%(lineno)d]  %(message)s',

datefmt='%a, %d %b %Y %H:%M:%S',

filename=filename,

filemode='w')


5、接口请求类封装


   安装第三方模块requests

pip install requests

  定义函数send_request,根据传入的方法类型分别去调用request的get,post,delete,put等方法去发送请求。send_request.py:

import  requests

from untils. log_trace import  *

#发送get请求

def get_request(url,data=None,headers=None):

res = requests.get(url=url,data=data,headers=headers)

return res

#发送post请求

def post_request(url,data,headers=None):

res = requests.post(url=url,data=data,headers=headers)

return res

#发送delete请求

def del_request(url,data=None,headers=None):

res = requests.delete(url,data=data)

return res

#发送put请求

def put_request(url,data,headers=None):

pass

def send_request(method,url,data=None,headers=None):

try:

logging.info(headers)

if headers:

if method == "GET":

return get_request(url,data,headers=headers)

if method == "POST":

return post_request(url,data=data,headers=headers)

if method == "DELETE":

return  del_request(url,data=data,headers=headers)

#put使用频率低,暂时不写

if method == "PUT":

return  put_request(url,data=data,headers=headers)

else:

logging.info("Header is null")

except Exception as e:

logging.info("send request fail:%s"%e)

  在untils_test.py中编写代码测试send_request方法,代码如下:

#coding:utf-8

from untils.send_request import send_request

def test_send_request():

url="http://127.0.0.1:9000/articles/"

headers = {

"X-Token":"0a6db4e59c7fff2b2b94a297e2e5632e"

}

res = send_request("GET",url,headers=headers)

print(res.json())

if __name__ == "__main__":

test_send_request()

  运行结果:

/usr/bin/python3.6 /home/stephen/IdeaProjects/apitest/untils/untils_test.py

{'status': 'BS.200', 'all_titles': {'amy1': 'alive', 'modifytest': 'alive', 'addTest': 'alive'}, 'msg': 'query articles sucess.'}

Process finished with exit code 0


6、Excel数据读取


  用例是放在Excel中的,用xlrd来读取数据,写数据需要用到xluntils,先安装:

pip install xlrd

pip install xluntils

  6.1 读取配置文件

  读取Excel数据,我们需要知道对应的行和列,列相对固定,在配置文件settings中定义,然后读取,行作为参数传入。conf/settings文件中的定义如下:

[excel]

case_no=0

case_name=1

is_run=2

case_level=3

case_header=4

case_cookies=5

req_type=6

case_url=7

case_body=8

expect_result=9

operator=10

actual_result=11

test_result=12

  在unitls/load_conf.py中编写读取配置的方法,获取各项列值的方法。lood_conf()函数需要传入两个参数:配置项字符串标识符,配置项类型。比如要读取excel下整数case_url:lood_conf("excel.case_url","int")。class excel_config()下定义返回各项列值的方法。

  完整代码如下:

import  configparser

'''

read conf from setting.conf

@:parameter:identstr,value_type

value_type:"int" or "str"

'''

def lood_conf(identstr,value_type):

cf = configparser.ConfigParser()

cf.read("../config/settings.conf")

idenlist = identstr.split('.')

if value_type == "int":

try:

value = cf.getint(idenlist[0],idenlist[1])

return  value

except (configparser.NoSectionError ,configparser.NoOptionError) as e:

print(e)

if value_type == "str":

try:

value = cf.get(idenlist[0],idenlist[1])

return value

except (configparser.NoSectionError ,configparser.NoOptionError) as e:

print(e)

'''

获取url,request body等的列号

'''

class excel_config():

#获取用例编号的列

def caseno_col(self):

return lood_conf("excel.case_no","int")

def casename_col(self):

return lood_conf("excel.case_name","int")

def isrun_col(self):

#print(lood_conf("excel.is_run","int"))

return lood_conf("excel.is_run","int")

def level_col(self):

return lood_conf("excel.case_level","int")

def header_col(self):

return lood_conf("excel.case_header","int")

def cookies_col(self):

return lood_conf("excel.case_cookies","int")

def reqtype_col(self):

return lood_conf("excel.req_type","int")

def caseurl_col(self):

return lood_conf("excel.case_url","int")

def casebody_col(self):

return lood_conf("excel.case_body","int")

def expectresult_col(self):

return lood_conf("excel.expect_result","int")

def actualresult_col(self):

return lood_conf("excel.actual_result","int")

def testresult_col(self):

return lood_conf("excel.test_result","int")

def test_operator_col(self):

return lood_conf("excel.operator","int")

  6.2 编写Excel操作类

  unitls/excel_tool.py中定义了获取用例编号,用例名称等方法,需要传入行。回写测试结果,回写实际结果方法需要传入两个参数:行,值。完整代码如下:

#coding:utf-8

import xlrd

from untils.log_trace import *

from xlutils.copy import copy

from untils.load_conf import excel_config

class excel_tool():

def __init__(self,excel_name):

self.curr_excel = xlrd.open_workbook(excel_name)

self.table = self.curr_excel.sheet_by_index(0)

#print(self.table.cell(1,1).value)

#实例化excel_config

self.config = excel_config()

self.rows = self.table.nrows

self.excel_name = excel_name

#获取用例编号

def get_caseno(self,row):

caseno = self.table.cell(row,self.config.caseno_col()).value

if caseno:

return caseno

else:

logging.info("case no is null")

return None

#获取用例名称

def get_casename(self,row):

casename = self.table.cell(row,self.config.casename_col()).value

return casename

#获取是否运行标志

def get_runflag(self,row):

run_flag = self.table.cell(row,self.config.isrun_col()).value

return run_flag

#获取用例级别

def get_caselevel(self,row):

caselevel = self.table.cell(row,self.config.level_col()).value

return caselevel

#获取请求url

def get_caseurl(self,row):

caseurl = self.table.cell(row,self.config.caseurl_col()).value

return caseurl

#获取请求body

def get_casebody(self,row):

case_body = self.table.cell(row,self.config.casebody_col()).value

return case_body

#获取header

def get_headerflag(self,row):

headerflag = self.table.cell(row,self.config.header_col()).value

return headerflag

#获取coocikes

def get_cookiesflag(self,row):

cookiesflag = self.table.cell(row,self.config.cookies_col()).value

return cookiesflag

#获取请求类型

def get_methodtype(self,row):

method_type = self.table.cell(row,self.config.reqtype_col()).value

return method_type

#获取预期结果

def get_expectres(self,row):

expect_res = self.table.cell(row,self.config.expectresult_col()).value

return expect_res

#获取测试结果

def get_testres(self,row):

test_res= self.table.cell(row,self.config.testresult_col()).value

return test_res

#获取操作符

def get_operator(self,row):

operator = self.table.cell(row,self.config.test_operator_col()).value

return operator

#回写测试结果到excel

def write_testres(self,row,value):

wbook = copy(xlrd.open_workbook(self.excel_name))

sheet = wbook.get_sheet(0)

sheet.write(row, self.config.testresult_col(), value)

wbook.save(self.excel_name)

#回写实际结果

def write_actualres(self,row,value):

wbook = copy(xlrd.open_workbook(self.excel_name))

sheet = wbook.get_sheet(0)

sheet.write(row, self.config.actualresult_col(), value)

wbook.save(self.excel_name)


7、用例组装


  有了Excel操作类,就可以方便读取数据和回填结果了。接下来,在unitls/run_main.py中来组装用例。组装之前,先获取是否运行的标志:

  运行标志为N,不组装,将用例标记为skiiped,回填测试结果到Excel文件中。

  运行标志为Y,开始组装用例并执行,并对比预期结果和实际结果。

  用例执行通过,将用例标记为pass,回填测试结果和实际结果,实际结果为接口的返回。

  用例执行失败,将用例标记为failed,回填测试结果和实际结果。

  接口鉴权需要用到的headers,先在run_main.py 中写死,这个问题后面解决,在上面的过程中,增加必要的日志,方便定位问题和查看用例的运行日志。完整代码如下:

#coding:utf-8

from untils.excel_tool import excel_tool

from untils.send_request import send_request

from untils.log_trace import *

from untils.check_result import CheckResult

import  json

headers = {

"X-Token":"0a6db4e59c7fff2b2b94a297e2e5632e"

}

class runner():

def __init__(self):

self.excel = excel_tool("../testcase/test.xls")

self.check = CheckResult()

def join_case(self):

global  skip_list,sucess_list,failed_list,skip_list

sucess_list = []

sucess_list = []

failed_list = []

skip_list = []

for row in range(1,self.excel.rows):

no = self.excel.get_caseno(row)

url = self.excel.get_caseurl(row)

isrun = self.excel.get_runflag(row)

name = self.excel.get_casename(row)

level = self.excel.get_caselevel(row)

data = self.excel.get_casebody(row)

expect_res = self.excel.get_expectres(row)

method = self.excel.get_methodtype(row)

hasheader = self.excel.get_headerflag(row)

operator = self.excel.get_operator(row)

if isrun == "Y":

logging.info("Begin to run test case : %s,case number :%s" %(name,no))

logging.info("Request method type is :%s" %method)

logging.info("Request URL:%s" %url)

logging.info("Request Body:%s" %json.dumps(json.loads(data),sort_keys=True,indent=2))

res = send_request(method,url,data=data,headers=headers)

is_sucess = self.check.cmpdict(eval(expect_res),eval(res.text),operator)

print(is_sucess)

if is_sucess:

sucess_list.append(name)

#回写测试结果

self.excel.write_testres(row,"pass")

#回写实际结果

self.excel.write_actualres(row,res.text)

logging.info("Test case %s run sucess." %name)

else:

failed_list.append(name)

print("fail",is_sucess)

#回写测试结果

self.excel.write_testres(row,"failed")

#回写实际结果

self.excel.write_actualres(row,res.text)

logging.error("Test case %s run fail." %name)

logging.info("Response is:%s" %json.dumps(res.json(),sort_keys=True,indent=2))

else:

skip_list.append(name)

self.excel.write_testres(row,"skipped")

def sum(self):

total = len(sucess_list)+len(failed_list) + len(skip_list)

failed = len(failed_list)

sucess = len(sucess_list)

logging.info("-----------------------------------------------------------")

logging.info("本次一共运行:%s 个用例" %total)

logging.info("本次运行通过:%s 个用例" %sucess)

logging.info("本次运行跳过:%s 个用例" %len(skip_list))

logging.info("跳过的用例:%s" %skip_list)

logging.info("-----------------------------------------------------------")


……


点击阅读原文全文


推荐阅读

点击阅读☞测试人员不得不小心那些职场套路

点击阅读☞接口测试框架实战与自动化进阶指南!

点击阅读☞教你如何快速搭建数据驱动自动化测试框架?

点击阅读☞从0到1 | 搭建自动化测试框架的思路及实例演示

点击阅读☞基于AI的移动端自动化测试框架的设计与实践

上文内容不用于商业目的,如涉及知识产权问题,请联系小编(021-64471599-8017)。



“阅读原文”查看全文!
爱我请给我好看!
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/32973
 
835 次点击