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

AIM框架介绍

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

设计思想

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

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

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

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

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

目录结构

case:测试用例

common:公共函数,全局变量

config:配置路径

data:数据文件

result:测试结果

util:工具类

run.py:用例执行入口

case

BaseCase

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

项目Case

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

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

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

common

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

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

Parewise.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:数据库相关操作。

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

Mail.py:发送邮件。

run.py

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

核心模块

Request

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

参数 说明
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文件中影响显示,可以指定文本进行替换。

自动设置token:

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

发送请求,并计算耗时:

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

Parewise

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

parewaise的概念可以百度一下。

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

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

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

比如参数

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

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

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

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

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 check_flag(self, flag, response, msg=True):
    """预期,实际"""
    msg = response.text if msg else None
    if isinstance(flag, list):
        b = False
        for f in flag:
            if f == response.json()['flag']:
                b = True
                break
        self.assertEqual(True, b, msg=msg)
    else:
        try:
            self.assertEqual(flag, response.json()['flag'], msg=msg)
        except json.JSONDecodeError:  # 返回的不是json,比如下载、404
            self.check_200(response, msg)
        except KeyError:
            self.check_200(response, msg)
​
def check_200(self, response, msg=True):
    self.assertEqual(200, response.status_code, msg=msg)

最简单的一个测试用例:

class Home(BaseCase):
    """首页"""
​
    @classmethod
    def setUpClass(cls):
        Var.token = login.get_token()
​
    def setUp(self):
        log(testname(self.__repr__()) + '\n')
        record([testname(self.__repr__())])
​
    def test_bankingSectorDisplay(self):
        """xxx"""
        p = {
            "url": full_url("xxx"),
            "body": {}
        }
        self.check_flag(1, request(p))

setUpClass,设置登录token。

setup,输出日志。

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交易日测试通过率

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

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

统计表格

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

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

排序:

# 按照通过率从小到大排序
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,确保调用正常。
全选测试 将所有参数尽可能多的全选上,调用接口。 一定程序上可以弥补结对测试的不足。
结对测试 如前文所述,关注两两组合的情况。

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

结束语

第一次写技术博客。

马上工作5年。

算是一个尝试吧。

接口自动化测试框架-AIM的更多相关文章

  1. 接口自动化测试框架-AIM3.0-开源+OOP

    这是3.0了,从1.0到2.0直接跨越到3.0,就是这么随意. 3.0的关键词一是开源,源码地址为https://github.com/dongfanger/AIM,二是OOP. 随着python的发 ...

  2. 接口自动化测试框架-AIM2.0

    跳转到3.0版本https://www.cnblogs.com/df888/p/12031649.html AIM是我用python搭建的第一款接口自动化测试框架,随着技术的提升,框架也在升级,故有了 ...

  3. 接口测试入门(4)--接口自动化测试框架 / list和map用法 / 随机选取新闻 (随机数生成) / 接口相关id映射

    一.接口自动化测试框架 为了更好的组织测试方法,测试用例并且持续集成,我们选择了  java+testNG(测试用例组织)+gitlab(代码版本管理)+Jenkins(持续集成工具) 作为一整套的自 ...

  4. python版接口自动化测试框架源码完整版(requests + unittest)

    python版接口自动化测试框架:https://gitee.com/UncleYong/my_rf [框架目录结构介绍] bin: 可执行文件,程序入口 conf: 配置文件 core: 核心文件 ...

  5. 接口自动化 [授客]基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0

    基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0   by:授客 QQ:1033553122     博客:http://blog.sina.com.cn/ishou ...

  6. 接口自动化 基于python+Testlink+Jenkins实现的接口自动化测试框架[V2.0改进版]

    基于python+Testlink+Jenkins实现的接口自动化测试框架[V2.0改进版]   by:授客 QQ:1033553122 由于篇幅问题,,暂且采用网盘分享的形式: 下载地址: [授客] ...

  7. 基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0

    基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0 目录 1. 开发环境2. 主要功能逻辑介绍3. 框架功能简介 4. 数据库的创建 5. 框架模块详细介绍6. Tes ...

  8. 【转】robot framework + python实现http接口自动化测试框架

    前言 下周即将展开一个http接口测试的需求,刚刚完成的java类接口测试工作中,由于之前犯懒,没有提前搭建好自动化回归测试框架,以至于后期rd每修改一个bug,经常导致之前没有问题的case又产生了 ...

  9. 【python3+request】python3+requests接口自动化测试框架实例详解教程

    转自:https://my.oschina.net/u/3041656/blog/820023 [python3+request]python3+requests接口自动化测试框架实例详解教程 前段时 ...

随机推荐

  1. Windows10 家庭版没有本地组策略解决方法

    windows 家庭版默认是没有本地组策略的, win+R运行gpedit.msc提示不存在 下面的代码保存一个cmdorbat 脚本文件add_gpedit.cmd, 并执行 add_gpedit. ...

  2. django -- Celery实现异步任务

    1. 环境 python==2.7 djang==1.11.2 # 1.8, 1.9, 1.10应该都没问题 celery-with-redis==3.0 # 需要用到redis作为中间人服务(Bro ...

  3. C++进阶书籍(转)

    推荐的阅读顺序:level 1从<<essential c++>>开始,短小精悍,可以对c++能进一步了解其特性以<<c++ primer>>作字典和课 ...

  4. easyui学习笔记14-拓展的基本验证规则

    /** * 扩展的基本校验规则, */ $.extend($.fn.validatebox.defaults.rules, { minLength : { // 判断最小长度 validator : ...

  5. leetcode 1. Two Sum [java]

    注意点: HashMap<Integer, Integer> return new int[]{}; 3 2 4 target:6 return null; public int[] tw ...

  6. 在 CentOS/Fedora 下安装 JAVA 环境

    介绍 本文介绍如何在 CentOS 7(6/6.5). Fedora.RHEL 上安装 Java.Java是一个流行的软件平台,允许您运行Java应用程序. 本文涵盖了以下Java版本的安装: Ope ...

  7. Vuex数据页面刷新丢失问题解决方案

    用Vue做项目开发很久了,对于vuex能用.会用,但是因为状态脱离页面和刷新丢失两个原因,一直都有种抵触,特别是一些简单的数据都是通过query或者本地存储就解决了,然而对于一些复杂内容,不可避免的还 ...

  8. Mysql双主 keepalived+lvs实现mysql高可用性

    MySQL复制 能够保证数据的冗余的同时可以做读写分离来分担系统压力,如果是主主复制还可以很好的避免主节点的单点故障.但是MySQL主主复制存在一些问题无法满足我们的实际需要:未提供统一访问入口来实现 ...

  9. Failed to load or instantiate TagLibraryValidator class: org.apache.taglibs

    在部署工程时,没有加入javax.servlet-api.jar(3.0.1) 和 standard.jar(1.1.2)两个jar包导致此问题. 另外,如果原来容器中有javax.servlet-a ...

  10. Python2.7-robotparser

    robotparser 模块,用于解析网站的 robots.txt 文件,robots.txt 文件是用于指定搜索引擎爬虫的访问权限的,此模块在 python3 中重命名为 urllib.robotp ...