接口自动化测试框架【AIM】

news2024/11/27 3:38:04

最近在做公司项目的自动化接口测试,在现有几个小框架的基础上,反复研究和实践,搭建了新的测试框架。利用业余时间,把框架总结了下来。

AIM框架介绍

AIM,是Automatic Interface Monitoring的简称,即自动化接口监测。是一种基于python unittest的自动化接口测试框架。

设计思想

框架根据python语言的特点,结合了面向对象和面向函数编程。

以高效编程为主要目的,避免为了封装而封装。轻配置,重编码。

接口测试的主要处理对象是参数。如果完全进行数据与代码的分离,就会造成变量,传参的冗余,降低编程效率。

于是从不做数据与代码分离出发,对于需要复用的参数,提取到类之外,视需要进行数据与代码的分离。

做到有的放矢。兼顾效率和复用性,迭代分离,更具实用性。

1552446647735

目录结构

1557469790003

case:测试用例

common:公共函数,全局变量

config:配置路径等

data:数据文件

result:测试结果

util:工具类

run.py:用例执行入口

run_mail.py:执行后自动发送邮件入口

case

BaseCase

所有Case的基类。

封装了requests库的post和get函数req,用于发送请求。

调用assertEqual等方法,封装了用例的断言。比如检查接口返回flag,检查接口状态200,检查值相等。

项目Case

测试系统的用例。按模块分别建立文件编写脚本。

Env.py:环境配置,包括url处理,登录对象login实例(用户名、密码),数据库对象dao实例(数据库连接)。

Public.py:公共模块。存放本系统公共的变量、函数、用例等。

common

Func.py:公共函数,比如获取时间日期,获取随机数,处理参数。

Login.py:登录模块,属于各系统通用,故放于此目录下。包括密码加密,验证码处理,强制登录。

Var.py:全局变量。比如token。

config

RelativePath.py:配置目录、文件的相对路径。

data

echarts数据存储csv文件,项目接口清单等。

result

log:日志。logging实现。支持输出到文件和打印控制台。文件暂时使用较少,主要打印控制台便于调试。

接口调用记录:输出每个测试方法调用接口的记录,包括参数、响应、耗时等。

自动化测试报告:HTMLTestRunner.py实现的html页面报告。

util

AutoCode.py:自动生成结构化测试代码。

CSV.py:csv相关函数封装。比如输出接口调用记录。

Excel.py:读取和存储excel文件。

Format.py:格式化。比如把浏览器复制的参数格式化为代码中带有缩进的json。

HTMLTestRunner.py:用于输出自动化测试报告。

Log.py:封装日志方法。

Mysql.py:数据库相关操作。

Parewise.py:结对测试。一种测试技术,后文详述。

Request.py:核心工具,封装接口发送请求。

Mail.py:发送邮件。

run.py

执行测试用例入口,可以选择执行一个或多个系统,也可以执行一个系统中一个或多个模块。

核心模块

BaseCase.req

通过requests封装的发送接口请求的方法。

定义在BaseCase类的内部。

参数说明
p将url、headers、body、method统一封装到一个json里面进行处理。
method='post'默认为post方法。接口以post居多。
jsondata='json'默认json参数。post方法的json或data,纯json使用json参数即可。对于receive_json这种dict,采用data参数。
loglevel=3默认为3。日志级别,输出请求、响应信息到控制台或接口调用记录.csv。
rtext=None一些get请求会返回html或pdf,在控制台或csv文件中影响显示,可以指定文本进行替换。

发送请求,并计算耗时:

        start = time.clock()
        if method == 'post':  # 关闭SSL认证
            if jsondata == 'json':
                r = self.timeoutTry("requests.post(p['url'], headers=p['headers'], json=p['body'], verify=False)", p)
            elif jsondata == 'data':
                r = self.timeoutTry("requests.post(p['url'], headers=p['headers'], data=p['body'], verify=False)", p)
            else:
                print('jsondata错误')
        elif method == 'get':
            r = self.timeoutTry("requests.get(p['url'], headers=p['headers'], params=p['body'])", p)
        else:
            print('method错误')
        end = time.clock()
        elapsed = decimal.Decimal("%.2f" % float(end - start))

其中的self.timeoutTry是为了处理响应超时,会在后续博文中介绍。

Parewise

结对测试。接口参数一般是多个,于是比较适合采用parewise进行用例设计。

parewaise的概念可以百度一下。

大概意思就是,大多数的bug都是条件的两两组合造成的,parewise就是针对两两组合的情况,设计测试用例。

算法为,如果某一组用例的组合结果,在其他组合中均出现,就删除该组用例,从而精简用例。

windows下有微软的PICT,txt文件录入参数后,命名行执行,就出来结果了。

比如参数

1552448368346

执行后结果,只有31条,精简了很多。

1552448425685

这个基本上一秒就出来结果了。

我自己参考网上算法写的,就要慢的多。

估计后面有时间了再看看能不能调优。

parewise算法:

cp = []  # 笛卡尔积
s = []  # 两两拆分
for x in eval('itertools.product' + str(tuple(param_list))):
    cp.append(x)
    s.append([i for i in itertools.combinations(x, 2)])

del_row = []
s2 = copy.deepcopy(s)
for i in range(len(s)):  # 对每个进行匹配
    t = 0
    for j in range(len(s[i])):  # 判断所有同时都存在其他中 且位置相同
        for i2 in [x for x in range(len(s2)) if s2[x] != s[i]]:  # 其他 只比对有效
            flag = False
            for j2 in range(len(s2[i2])):
                if s[i][j] == s2[i2][j2] and j == j2:
                    t = t + 1
                    flag = True
                    break
            if flag:
                break
    if t == len(s[i]):
        del_row.append(i)
        s2.remove(s[i])

return [cp[i] for i in range(len(cp)) if i not in del_row]

网上的例子是用的index函数。在我写过程中,发现这里有个坑。比如list中存在相同元素,就始终返回前一个匹配的索引,结果就会有问题。我就完全避免了index函数。不知道哪个是对的,目前满足使用需要,将就着用了。有点小尴尬。

Case

BaseCase断言:

    def checkFlag(self, p, r):
        """预期,实际"""
        err = str([p['url'], p['body'], r.text])
        try:
            b = False
            if (r.json()['flag'] in [1, '1', '', None, 'statistic_by_result', 0,
                                     "0", 'struct_product', 'v_select_jz_single']
                    or r.json()['message'] in ("暂无数据", "未查询到数据")):
                b = True
            self.assertEqual(True, b, msg=err)
        except (json.JSONDecodeError, KeyError):  # 1.返回的不是json,比如下载、404  2.无flag
            self.assertEqual(200, r.status_code, msg=err)

最简单的一个测试用例:

from case.PyPlatform2_0_2.Public import *

class Home(BaseCase):
    """首页"""

    def setUp(self):
        log(testname(self.__repr__()) + '\n')
        record([testname(self.__repr__())])

    def test(self):
        """xxx"""
        self.req({
            "url": full_url("xxx"),
            "body": {}
        })

setup,输出日志。

Token

因为公司登陆用的token,跟cookie类似,保留登陆状态,避免重复登陆。

如何处理token也是框架设计的一个要点。

1557471452464

Env设置token,因为每个系统的登陆参数值都不一样。

Var.token = login.get_token()

BaseCase.req在每次请求时获取token,从而免登录。

if "headers" not in p.keys():
    p['headers'] = {'token': ''}
    p['headers']['token'] = Var.token

CSV

写文件:

if not os.path.exists(path):
    f = open(path, 'a', newline='')
    a = csv.writer(f)
    a.writerow(title)
    f.close()

f = open(path, 'a', newline='')
a = csv.writer(f)
try:
    a.writerow(d)
except UnicodeEncodeError:
    d[4] = "Unicode隐藏"  # response
    a.writerow(d)
f.close()

if get_file_size(path) >= 50 * 1024 * 1024:  # 超过50M删除文件
    os.remove(path)
    record(title)

traceback自动生成文件名:

def _sys_name():
    t = str(traceback.extract_stack())
    b = True
    for x in os.listdir(case_dir):
        if x not in ["BaseCase.py", "__pycache__"]:
            if x in t:
                return x + "接口调用记录" + current_date() + ".csv"
    if b:
        print("request找不到sysname")
        print(t)

HTMLTestRunner

根据通用的版本,也是参考网上一些现有的美化代码,综合了一下,根据自己需求做了改造。

近20交易日测试通过率

1552449137641

加了一个echarts,把最近20交易日的测试通过率,通过折线走势图的方式展示出来。监测系统稳定性。

数据存放和读取在data目录的csv文件中。

统计表格

1552449314757

按项目进行分组统计,增加测试说明一列,按颜色区别测试结果状态,可点击查看详细描述和错误信息。

同时优化了整体的样式效果。

排序:

# 按照通过率从小到大排序
passrate_value = []
for key in passrate:
    if key != 'total':
        passrate_value.append(float(passrate[key].replace('%', '')))

passrate_value.sort()

保存折线图数据:

today = datetime.datetime.now().strftime('%Y-%m-%d')
if '--' not in names:  # 跑单个系统不存
    if dao_is_trade_date(today):  # 非交易日不存
        with open(self.rct20_path, "r") as f:  # 读取数据
            lines = csv.reader(f)
            lines = list(lines)
            for lin in lines:
                lin[0] = lin[0].replace('月', '-')
                lin[0] = lin[0].replace('日', '')
        rct_data = lines
        # print(rct_data)

        nowdate = datetime.datetime.now().strftime('%m-%d')
        # 如果有重复日期,先删
        l = len(rct_data)
        while l != 0 and nowdate == rct_data[l - 1][0]:
            rct_data.pop(l - 1)
            l = len(rct_data)

        for pt in self.passrate_tl:
            n = pt[0]
            v = pt[1]
            row = []
            row.append(str(nowdate))
            row.append(str(n))
            row.append(str(v).replace('%', ''))
            rct_data.append(row)
        # 只存近20条
        row_20 = len(names) * 20
        if len(rct_data) > row_20:  # 超过20条
            for i in range(0, len(names)):
                rct_data.pop(0)

        with open(self.rct20_path, 'w', newline='') as f:
            writer = csv.writer(f)
            writer.writerows(rct_data)

拼接折线图数据用于展示:

while ri < len(rct_data):  # 遍历 ->s_data
    scan = []
    while ri < len(rct_data) and rct_data[ri][0] == trade_date[di]:
        s_data[rct_data[ri][1]].append(rct_data[ri][2])
        scan.append(rct_data[ri][1])
        ri += 1
    chg = list(set(names) ^ set(scan))  # 差集
    for c in chg:
        s_data[c].append('--')  # 增加/减少的项目,为'--'
    di += 1

series = []  # 系列序列
s_names = s_data.keys()
for k in s_names:
    s = {}  # 单个系列
    s['name'] = k
    s['type'] = 'line'
    if s_data != {}:
        s['data'] = s_data[k]
    series.append(s)

这部分代码是很久之前写的了,代码应该是不够简洁、高效、规范滴,是可以优化滴。偷了懒没有重构了。

用例设计

测试类型描述
冒烟测试所有接口写单独的test,确保调用正常。
全选测试将所有参数尽可能多的全选上,调用接口。
一定程序上可以弥补结对测试的不足。
结对测试如前文所述,关注两两组合的情况。

参数值,部分采用随机数。也视需求,从数据库或其他接口获取数据。

【接口自动化测试入门】从0到1落地实施接口自动化测试框架

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1320694.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Idea代码走查工具FindBus使用以及缺陷分析

1. 简介 Findbugs是一个静态分析工具&#xff0c;它检查类或者jar文件&#xff0c;将字节码与一组缺陷模式进行对比以发现可能的问题。利用这个工具可以在不实际运行程序的情况下对软件进行分析。可以帮助改进代码质量。Findbugs提供了方便操作的可视化界面&#xff0c;同时&a…

[计网00] 计算机网络开篇导论

目录 前言 计算机网络的概念 计算机网络的分层 计算机网络的分类 网络的标准化工作和相关组织 计算机网络的性能指标 前言 计算机网络在我们的日常生活中无处不在 在网络会有各种各样的协议和封装 保证我们的信息完整,无误的在各个客户端之前传输 计算机网络的概念 四…

Unity与Android交互通信系列(2)

在上一篇文章中&#xff0c;我们介绍了Unity和Android交互通信的原理及在Unity中直接调用Java代码的方式&#xff0c;但没有给出代码示例&#xff0c;下面通过实际例子演示上篇文章中AndroidJavaClass、AndroidJavaObject两个类的基本用法&#xff0c;由于交互通信涉及到两端&a…

1KW逆变器UPS纯正弦波方案

硬件方案--110V方案 本套逆变器方案分110V输出以及220V输出&#xff0c;电池最大电压是48V&#xff0c;包括了LCD。110V方案主控使用的dsp是MICROCHIP(美国微芯)的dsPIC33FJ16GS504芯片&#xff0c;ACDC控制器是TOP250YN&#xff0c;运算放大器包含LM358、MCP6022&#xff0c;电…

Spring IOC 原理(二)

Spring IOC 原理 概念 Spring 通过一个配置文件描述 Bean 及 Bean 之间的依赖关系&#xff0c;利用 Java 语言的反射功能实例化Bean 并建立 Bean 之间的依赖关系。 Spring 的 IoC 容器在完成这些底层工作的基础上&#xff0c;还提供了 Bean 实例缓存、生命周期管理、 Bean 实…

【数据结构复习之路】图(严蔚敏版)两万余字超详细讲解

专栏&#xff1a;数据结构复习之路 复习完上面四章【线性表】【栈和队列】【串】【数组和广义表】【树和二叉树】&#xff0c;我们接着复习 图&#xff0c;这篇文章我写的非常详细且通俗易懂&#xff0c;看完保证会带给你不一样的收获。如果对你有帮助&#xff0c;看在我这么辛…

我愿称其为神器-vscode-vim自动切换输入法

我愿称其为神器-vscode-vim自动切换输入法 smartinput在linux下无效 首先在 文件->首选项->配置 找到setting.json 在这个github中给出了详细的config.json配置文件 https://github.com/daipeihust/im-select/blob/master/README_CN.md 因为我使用的是ibus,在将set…

javaSE学习-3-数组的定义与使用

1 数组的创建及初始化 int[] array1 new int[10]; // 创建一个可以容纳10个int类型元素的数组 double[] array2 new double[5]; // 创建一个可以容纳5个double类型元素的数组 String[] array3 new double[3]; // 创建一个可以容纳3个字符串元素的数组 2 基本类型变量与…

新人做自动化测试,记住这5点涨薪指日可待...

关于新人如何做好自动化测试&#xff0c;以下是我个人的一些思考。 01、测试基础的重要性 作为一名测试新人&#xff0c;测试基础非常非常重要。这里说的基础&#xff0c;不仅仅是什么是软件测试、软件测试的目的&#xff0c;而是测试用例的设计能力。 因工作的原因&#xf…

教育机构小程序管理系统的全方位优化

随着互联网的快速发展&#xff0c;线上教育也日益受到人们的关注和欢迎。为了满足广大学生和家长的需求&#xff0c;教育机构纷纷开发出自己的小程序管理系统。本文将详细介绍如何使用乔拓云平台&#xff0c;一键开发出自己的教育机构小程序管理系统。 1.进入乔拓云后台 首先&…

记一次java for循环改造多线程的操作

背景 今天在开发质量平台时需要获取某些数据&#xff0c;要请求公司某个工程的OpenAPI接口A。此接口为返回通用数据的接口&#xff0c;且接口本身的RT都在2&#xff5e;3秒之间。使用该接口&#xff0c;需要进行两次循环获取&#xff0c;然后对返回数据进行处理组装&#xff0…

弹窗“由于找不到xinput1_3.dll,无法继续执行代码”的几种解决方法分享

日常中&#xff0c;我们在使用电脑过程中&#xff0c;偶尔会遇到一些错误提示“由于找不到xinput1_3.dll,无法继续执行代码”&#xff0c;这个报错会让程序无法正常运行的情况。那么&#xff0c;xinput1_3.dll到底是什么&#xff1f;它丢失会对计算机产生什么影响呢&#xff1f…

健康卤味思想引领市场新潮流,卤味市场迎来健康变革

健康卤味思想正在逐渐渗透到卤味市场中&#xff0c;引领着消费者对于卤味产品的选择和需求。这一变革不仅为消费者带来了更加健康、美味的卤味产品&#xff0c;也为卤味市场注入了新的活力。 一、健康卤味思想的兴起 随着消费者对于健康饮食的关注度不断提高&#xff0c;健康卤…

频谱论文:基于张量Tucker分解的频谱地图构建算法

#频谱# [1]陈智博,胡景明,张邦宁 郭道省.(2023).基于张量Tucker分解的频谱地图构建算法.电子与信息学报(11),4161-4169. &#xff08;陆军工程大学&#xff09; 研究内容 将动态电磁环境的时变频谱地图建模为3维频谱张量&#xff0c;通过张量Tucker分解提取出具有物理意义的核…

Linux---Ubuntu软件卸载

1. 软件卸载的介绍 Ubuntu软件卸载有两种方式: 离线安装包的卸载(deb 文件格式卸载&#xff09;在线安装包的卸载(apt-get 方式卸载) 2. deb 文件格式卸载 命令格式: sudo dpkg –r 安装包名 -r 选项表示安装的卸载 dpkg 卸载效果图: 3. apt-get 方式卸载 命令格式: …

svn 安装

安装系统 ubuntu 22 安装命令&#xff1a; sudo apt-get install subversion 创建第一个工程&#xff1a; 创建版本库、项目 1、先创建svn根目录文件夹 sudo mkdir /home/svn 2、创建项目的目录文件夹 sudo mkdir /home/svn/demo_0 svnadmin create /home/svn/demo_0 配置&a…

【Redis】五、Redis持久化、RDB和AOF

文章目录 Redis持久化一、RDB&#xff08;Redis DataBase&#xff09;触发机制如何恢复rdb文件 二、AOF&#xff08;Append Only File&#xff09;三、扩展 Redis持久化 面试和工作&#xff0c;持久化都是重点&#xff01; Redis 是内存数据库&#xff0c;如果不将内存中的数据…

单元测试计划、用例、报告、评审编制模板

单元测试支撑文档编制模板&#xff0c;具体文档如下&#xff1a; 1. 单元测试计划 2. 单元测试用例 3. 单元测试报告 4. 编码及测试评审报告 软件项目相关资料全套获取&#xff1a;软件项目开发全套文档下载-CSDN博客 1、单元测试计划 2、单元测试用例 3、单元测试报告 4、编码…

使用数组模拟栈的相关操作【栈1.1】

public class ArrayStackDemo {public static void main(String[] args) {ArrayStack arrayStack new ArrayStack(4);Scanner sc new Scanner(System.in);boolean loop true;char key ;while (loop) {System.out.println("栈操作菜单项");System.out.println(&q…

python绘图总结

1 二维图像 1.1 二维曲线 plot(x, y, ls"-", lw1.5, labelNone)x, y&#xff1a;横坐标和纵坐标ls&#xff1a;颜色、点标记、线型列表&#xff0c;如 ls‘r*-’ 表示红色实线、*形点&#xff0c;ls‘g.’ 表示绿色散点lw&#xff1a;线宽度label&#xff1a;线标签…