python_atp框架

atp接口自动化框架

程序说明:接口自动化框架,主要是通过读Excel中的接口用例,然后自动化跑用例

实现功能:读Excel,调用接口,结果校验,写报告,及发送报告

依赖软件:程序运行需要使用request,xlrd,nnlog,yagmail,xlutils,faker,jsonpath第三方模块,安装命令pip3 install 模块名称

程序运行:Python bin/start.py

程序结构,如下图:

 

代码如下:

1、setting配置文件

import  os
import faker

#邮箱信息
email_info={
    'user': 'xx@qq.com',
    'host': 'smtp.qq.com',
    'password': 'XX'
}

#发件人和抄送人信息
to=['XX@qq.com']
cc=['XX@qq.com']

#每个目录的路径
base_path=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
log_path=os.path.join(base_path,'logs','atp.log')
report_path=os.path.join(base_path,'report')
cases_path=os.path.join(base_path,'cases')

#case文件前缀
case_file_start='case'

#测试数据生成
f=faker.Faker(locale='zh-CN')
fun_map={
    "<phone>":f.phone_number,
    "<id_card>":f.ssn,
    "<email>":f.email,
    "<name>":f.name,
    "<addr>":f.address,
    "<password>":f.ssn
}

#测试环境配置,可通过修改evn,进行线上,线下及准生产环境的自由切换
evn='test'
host_map={
    "test":"http://XX",
    "dev":"http://XX/",
    "pre":"http://XX/",
}
host=host_map[evn]

 2、lib下的各功能模块

首先是读Excel,读用例模块

import traceback
import xlrd
import nnlog
from config.setting import log_path,fun_map


class Read_Case:
    def __init__(self):
        self.log = nnlog.Logger(log_path) #声明日志对象

    #用例读取函数
    def read_excel(self,xls_path):
        case_list = []  #定义用例存放list
        try:
            book = xlrd.open_workbook(xls_path) #读取用例文件
            sheet1 = book.sheet_by_index(0)   #声明使用文本簿第0个
            for row in range (1,sheet1.nrows): #从第1行开始读取用例,第0行是表头,所以不用读取
                row_case=sheet1.row_values(row)[1:7] #读取1-6列数据,放入list
                row_case[2]=self.parameter_change_dic(self.replace_parameter(row_case[2])) #对入参进行参数化替换及数据转换为字典
                row_case[3]=self.parameter_change_dic(self.replace_parameter(row_case[3])) #对请求头进行参数化替换及数据转为字典
                case_list.append(row_case) #逐行用例放入list中
            return  case_list #返回用例集

        except Exception as e:
            #如果报错,报错信息写入LOG
            self.log.error("读取用例文件出错,文件名是:%s"%xls_path)
            self.log.error("具体错误信息是%s"%traceback.format_exc())

   #参数化函数
    def replace_parameter(self,str):
        for parameter in fun_map.keys(): #变量参数化名称
            if parameter in str: #如果字符串中存在定义的参数化名进行参数化替换
                str=str.replace(parameter,fun_map[parameter]()) #把随机生成的参数化值替换到STR中
        return  str #把参数化替换后的STR返回

    #传参字符串转换字典
    def parameter_change_dic(self,str):
        parameter_dic={} #字典
        if str.strip(): #如果字符串非空
            middle_value=str.split(',') #先对字符串逗号分隔放入LIST
            for value in middle_value: #对list每一项进行KEY和VALUE放入字典
                kname,vname=value.split('=')#等号区分,分别读取KEY和VALUE值
                parameter_dic[kname]=vname #逐项加入字典
        return parameter_dic #返回转换后的字典

执行用例功能模块

import traceback
import requests,nnlog
from config.setting import host,log_path
from urllib.parse import urljoin


class Test_Request:
    def __init__(self,url,method,data,header,is_json=''): #参数传参与EXCEL顺序保持一致
        self.method=method.lower()
        self.url=urljoin(host,url) #host+接口名称拼接,urljoin可以拼接连接,无需考虑多斜杠,少斜杠的问题
        self.data=data #传参
        self.is_json=is_json #是否是JSON格式
        self.header=header #请求头
        self.log=nnlog.Logger(log_path) #日志对象声明
        self.test_request() #类中调用方法,声明对象后无需单独执行方法

    def  test_request(self):
        try:
            if self.is_json=='': #如果是json格式,请求参数用JSON
                case_result=requests.request(self.method,self.url,json=self.data,headers=self.header).json()
            else: #如果不是JSON格式,请求参数用data
                case_result=requests.request(self.method,self.url,data=self.data,headers=self.header).json()

        except Exception as e: #上面的请求出错后,就行写日志
            self.log.error('请求 %s的时候出错了,请求参数是:%s,错误信息是 %s' % (self.url, self.data, traceback.format_exc()))
            self.result = {"msg": "请求接口出错了", "error_msg": traceback.format_exc()} #这种日志写法,防止出错后,后续用例无法执行
            self.text = ' {"msg":"请求接口出错了","error_msg":%s} ' % traceback.format_exc() #这种日志写法,防止出错后,后续用例无法执行
        else:
            self.result=case_result #JSON格式的返回结果
            self.text=str(case_result) #返回结果转字符串类型

处理接口返回结果,实际结果与预期对比

import nnlog
from config.setting import  log_path
import jsonpath

class Test_Response:
    def __init__(self,check_str,response_str):
        self.log = nnlog.Logger(log_path) #声明日志对象
        self.check_str=check_str #预期结果
        self.response_str=response_str #实际返回结果
        self.status='通过' #执行状态
        self.reason="都通过啦" #不通过的原因
        self.check_response() #类中调用方法,声明对象后无需单独执行方法

    def check_response(self):
        symbol = ['!=', '>=', '<=', '=', '>', '<'] #符号库
        middle_value=self.check_str.strip().split(',') #对预期字符串去空格,逗号分隔
        for c_value in middle_value: #遍历预期list
            for s_mark in symbol: #遍历符合库
                if s_mark in c_value: #假如符号在本次遍历的预期串中,比如encode=0
                    v_key,v_value=c_value.strip().split(s_mark) #预期串按符号分隔
                    case_result=self.get_value(self.response_str,v_key) #获取实际结果中包含该KEY的值
                    s_mark="==" if s_mark=='=' else s_mark #假如符号是=号,变==,为实际结果和预期结果对比
                    code="%s %s %s"%(case_result,s_mark,v_value) #实际结果,符号,预期结果组合
                    code_result=eval(code) #字符串执行命令
                    if not code_result: #假如实际与预期不符,打印日志
                        self.reason = 'key是%s,运算的代码是%s' % (v_key, code)
                        self.log.error(self.reason) #输出错误原因
                        self.status = '失败' #执行状态为失败
                        return False
                    break
        return True

    def get_value(self,c_result, k_value):
        '这个函数是用来从返回结果里面获取key的'
        result = jsonpath.jsonpath(c_result, '$..%s' % k_value) #获取key为k_value的值
        if result: #假如result不为空
            return result[0] #返回获取到的第一个
        return '' #否则返回空

 写报告

import time
import xlrd
import nnlog
from xlutils import copy
import os
from config.setting import log_path, report_path

log=nnlog.Logger(log_path)
def write_excel(file_name,result_list):
    log.debug('现在开始写报告了:文件名是%s 内容:%s'%(file_name,result_list)) #写报告日志,注意如果返回结果太大,请不要打印result_list
    book=xlrd.open_workbook(file_name) #打开用例文件
    new_book=copy.copy(book) #复制该文件
    sheet=new_book.get_sheet(0) #获取第0个sheet
    for row,result in enumerate(result_list,1): #遍历返回结果列表,行从第1行开始写
        for col,value in enumerate(result[1:],7): #遍历返回结果且从下标1开始,因为第一个结果放请求参数,列从第7列开始
            sheet.write(row,col,value) #遍历写实际结果,原因,状态
        sheet.write(row,3,result[0]) #最后写请求参数,也就是更新请求参数为实际发送请求时的参数值
    file_name=os.path.split(file_name)[-1].replace('xlsx','xls') #获取文件名,且把xls替换为xlsx
    new_file_name=time.strftime('%Y%m%d%H%M%S')+"_"+file_name #新文件名称有当前时间+原文件名构成
    abs_path=os.path.join(report_path,new_file_name) #新文件名+报告地址,构成最新的文件路径
    new_book.save(abs_path) #文件保存到报告路径下
    log.debug("报告生成完成,文件名是%s"%abs_path) #打印报告地址
    return  abs_path #返回报告地址

写邮件

import traceback
import yagmail
import time
import nnlog
from config.setting import email_info,cc,to,log_path

log=nnlog.Logger(log_path) #日志对象声明
def send_mail(all_num,pass_num,file_name):
    log.debug('开始发送邮件') #发送邮件日志
    subject = "%s---接口测试结果" % time.strftime('%Y-%m-%d %H:%M:%S') #邮件标题
    content = '''
       各位好:
               "本次接口测试完成,结果如下:测试用例总共【%s】条,通过用例【%s】条,失败用例【%s】条"
               详细信息请看附件
       '''%(all_num,pass_num,all_num-pass_num) #邮件内容
    try:
        mail=yagmail.SMTP(**email_info) #解包方式传入参数
        mail.send(to=to,cc=cc,subject=subject,contents=content,attachments=file_name) #发送邮件
    except Exception as e:
        log.error("发送邮件出错了,错误信息是:\n%s"%traceback.format_exc()) #捕获错误信息
    else:
        log.info("发送邮件成功") #发送成功日志

启动自动化文件

from config.setting import cases_path,case_file_start,log_path
from lib.parse_response import Test_Response
from lib.request import Test_Request
from lib.read_case import Read_Case
import os
from lib.mail import send_mail
from lib.write_report import write_excel
import nnlog
log=nnlog.Logger(log_path) #声明日志对象

class CaseRun:
    all_num=0 #总用例数
    pass_num=0 #通过用例数
    #获取用例函数
    def get_case(self):
        excel_list=[] #用例文件列表
        for file in os.listdir(cases_path):#遍历用例文件夹下的文件列表
            if file.startswith(case_file_start) and (file.endswith("xls") or file.endswith("xlsx")): #如果是规定的用例格式文件
                abs_path=os.path.join(cases_path,file) #文件名和路径拼接
                excel_list.append(abs_path) #用例文件路径放入用例文件list
        return excel_list #返回用例文件list
    #执行用例用例
    def run_case(self,file_name):
        read_case_obj=Read_Case() #声明读用例对象
        case_list=read_case_obj.read_excel(file_name) #对用例且放入用例list
        response_list=[] #声明返回结果list
        for case in case_list: #遍历用例list
            self.all_num+=1  #每次循环用例总数加1
            req_obj=Test_Request(*case[:5]) #解包方式传入用例的URL,data,method,is_json,header
            response_obj=Test_Response(case[-1],req_obj.result) #预期与实际结果对比
            if response_obj.status=='通过': #加入预期与实际结果对比,状态返回通过
                self.pass_num+=1 #通过数加1
            response_list.append([str(req_obj.data),req_obj.text,response_obj.reason,response_obj.status]) #通过还是失败,需要把实际请求参数,返回结果,原因,状态放入返回结果list
        return write_excel(file_name,response_list) #返回报告地址

    #主函数
    def main(self):
        report_list=[] #报告地址list
        excel_list=self.get_case() #用例文件列表
        for excel in excel_list: #循环文件列表
            report_name=self.run_case(excel) #执行用例
            report_list.append(report_name) #每个用例的报告加入到报告list
        send_mail(self.all_num,self.pass_num,report_list) #发送邮件
        log.debug('运行完成') #运行成功


if __name__=='__main__':
    run=CaseRun() #实例化主程序对象
    run.main() #调用主方法,执行自动化测试用例

 备注:当然还可以根据该框架更加丰富一下,比如测试数据通过数据读取,或者写方法自动生成,或外部文件读取,另外也可加入多种接口请求,比如XML等

转载于:https://www.cnblogs.com/xiaokuangnvhai/p/11242420.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值