接口自动化测试实践

先说结论。

覆盖接口:300个。

覆盖模块:12个,其中二级模块47个。

开发模式下,调用接口次数:6828次,脚本运行耗时1h18min3s。

上线模式下,调用接口次数:1257次,脚本运行耗时15min46s。

该系统已稳定运行,本次测试过程中,发现了4个隐藏bug。

此次实践是基于前面分享的几篇博文进行的。

测试框架 接口自动化测试框架-AIM
测试思想 结对测试vs随机测试parewise算法性能优化(用例设计层面)
接口工具 F12开发者工具,Postman,Fiddler

编码的难点在于如何总结出各模块各接口的规律,

以尽量简化的代码,尽可能地覆盖更多的场景。

举个例子,下面这两段代码,就是在摸索出代码参数规律后写出来的。

eg1:

productList = [("1", "3", sample(["5", "6", "7", "8"], 2)),
               ("1", "4", ["9", "10"]),
               ("1", "5", sample(["11", "12", "13"], 2)),
               ("1", "6", ["14", "15"]),
               ("2", "3", sample(["5", "6", "7", "8"], 2)),
               ("2", "4", ["9", "10"]),
               ("2", "7", ["16", "17"])]
for product in productList:
    for monitorLevel in ("1", "2", "3"):
        self.req({
            "url": full_url("xxx"),
            "body": {"xxx": monitorLevel, "xxx": "3", "xxx": product[0],
                     "xxx": product[1],
                     "xxx": product[2]}
        })

eg2:

def test_portrait(self):
    # xxx
    table = [("1", "xxx"),  # xxx
             ("2", "xxx"),  # xxx
             ("3", "xxx"),  # xxx
             ("4", "xxx"),  # xxx
             ("5", "xxx"),  # xxx
             ("6", "xxx"),  # xxx
             ("7", "xxx"),  # xxx
             ("8", "xxx")]  # xxx
    data = list()
    for t in table:
        field = [x['COLUMN_NAME'] for x in
                 dao.select_dict('''select * from information_schema.COLUMNS t where table_name=\'%s\';''' % t[1])
                 if x['COLUMN_NAME'] not in ['xxx', 'xxx']]
        data.append({"xxx": t[0], "field_name": field})
    self.req({
        "url": full_url("xxx"),
        "body": {"xxx": pub.xxx(1)[0], "data": data}
    })

参数是接口测试最核心的部分,怎么处理就决定了接口测试的效率。

1、单选/多选

单选

"quarter": ("3", "4", "5", "6")

多选

checkbox("1,2,3,4,6,5")

checkbox是对多选项参数进行了处理:

def checkbox(option, j=None):
    """
    :param option:
    :param j: 组装参数的方式 list无 str默认',' 可以指定
    :return:
    """
    if j is not None:
        if isinstance(option, str):
            option = option.split(j)
        return j.join(option), j.join(sample(option, random.randint(1, len(option) - 1)))
    if j is None:
        if isinstance(option, str):
            j = ','
            option = option.split(j)
            return j.join(option), j.join(sample(option, random.randint(1, len(option) - 1)))
        if isinstance(option, list):
            return option, sample(option, random.randint(1, len(option) - 1))

兼顾了“1,2,3”和[1,2,3]两种组装参数的方式。

2、相互联动的参数

也就是说参数a的变化联动改变参数b。

一种方式是构建元组List,循环遍历

tz_zjbd = [(checkbox("xxx"), ""),  # xxx
                   ("", checkbox("xxx"))]  # xxx
        tz_qixian = [(checkbox("1,2,3,4,5,6"), "", ""),
                     ("", "0", "500")]  # xxx
        relate = [(tz_zjbd[0], tz_qixian[0]),
                  (tz_zjbd[1], tz_qixian[1])]
        pw = list()
        for rel in relate:
            p = {
                "url": None,
                "body": {
                    "content": [
                        {
                            "xxx": "2018-01-01",
                            "xxx": date("2018-01-01", "2019-03-01"),
                            "xxx": "2018-01-01",
                            "xxx": date("2018-01-01", "2019-03-01"),
                            "xxx": checkbox("xxx"),
                            "xxx": "0",
                            "xxx": "100",
                            "xxx": "0",
                            "xxx": "100",
                            "xxx": "0",
                            "xxx": "100",
                            "xxx": checkbox("1,2"),
                            "xxx": checkbox("1,2,3,4,5,6,7"),
                            "xxx": "",
                            "xxx": rel[1][0],
                            "xxx": checkbox("xxx"),
                            "xxx": checkbox("1,2,3,4,5,6"),
                            "xxx": checkbox("1,2,3"),
                            "xxx": ','.join(pub.bankName(3)),
                            "xxx": checkbox("1,2"),
                            "xxx": "理财",
                            "xxx": rel[1][1],
                            "xxx": rel[1][2],
                            "xxx": ','.join(pub.cityName(5)),
                            "xxx": rel[0][0],
                            "xxx": rel[0][1],
                            "xxx": "1",
                            "xxx": "1",
                            "xxx": "1",
                            "xxx": "1",
                            "xxx": "1",
                            "xxx": "1",
                            "xxx": "",
                            "xxx": "asc"
                        }
                    ]
                }
            }
            pw = pw + parewise(p['body']["content"][0])

一种方式是拆开分别处理

p = {
            "url": full_url("xxx"),
            "body": {
                "xxx": checkbox("1,2,3"),
                "xxx": checkbox("1,2"), "xxx": checkbox("1,2,3"),
                "xxx": checkbox("1,2,3,4,6,5"),
                "xxx": checkbox("1,2,3,4,6,5"),
                "xxx": date('2018-01-01', '2018-05-01'),
                "xxx": date('2018-05-02', '2019-01-01'), "xxx": ("1", "2"),
                "xxx": ("area_ch", "all_ch"), "xxx": "", "xxx": ("1", "2")}
        }
        for x in parewise(p['body']):
            p['body'] = x
            self.req(p)
        area_list = sample(
            """'海南省','安徽省','福建省','江西省','山东省','河南省','湖北省','湖南省','广东省','上海','广西壮族自治区',
                '四川省','贵州省','云南省','西藏自治区','陕西省','山西省','甘肃省','青海省','宁夏回族自治区','新疆维吾尔自治区',
                '天津','重庆','内蒙古自治区','辽宁省','吉林省','黑龙江省','江苏省','北京','河北省','浙江省'""".split(','),
            20)
        p = {  # 省份
            "url": full_url("xxx"),
            "body": {
                "xxx": checkbox("1,2,3"),
                "xxx": checkbox("1,2"), "xxx": checkbox("1,2,3"),
                "xxx": checkbox("1,2,3,4,6,5"),
                "xxx": checkbox("1,2,3,4,6,5"),
                "xxx": date('2018-01-01', '2018-05-01'),
                "xxx": date('2018-05-02', '2019-01-01'), "reports_type": ("1", "2"),
                "xxx": "province_ch", "xxx": checkbox(area_list, ","), "xxx": ("1", "2")}
        }
        for x in parewise(p['body']):
            p['body'] = x
            self.req(p)

视情况怎么方便怎么来。

3、接口依赖

接口的参数需要从另外接口的返回数据获取。

r = self.req({
            "url": full_url("xxx"),
            "body": {}
        })
        for content in r.json()['content']:
            for indexList in content['indexList']:
                self.req({
                    "url": full_url("xxx"),
                    "body": {
                        "indexCode": indexList['indexCode'],
                        "searchDate": "year1"
                    }
                })

4、从数据库取测试数据

s = dao.select_dict("""SELECT * FROM xxx""")
p = {
    "url": full_url(url),
    "body": {
        "page": 1,
        "pageSize": 15,
        "xxx": tuple(sample([x['doc_issuing_agency'] for x in s], 2)),
        "xxx": tuple(sample([x['doc_name'] for x in s], 2)),
        "xxx": tuple(sample([x['post_no'] for x in s], 2)),
        "xxx": tuple(sample([date2str(x['publish_date']) for x in s], 2)),
        "xxx": tuple(sample([date2str(x['publish_date']) for x in s], 2)),
        "xxx": ""
    }
}
for x in parewise(p['body']):
    p['body'] = x
    self.req(p)

5、请求超时的问题,可以参阅这篇‘Unexpected EOF‘ ‘远程主机强迫关闭了一个现有的连接‘ 如何处理

6、判断flag

最初的方案是每个接口返回flag不一样,在每个接口返回后,在用例中通过将flag和响应,传参给封装函数做判断。

最新的方案是综合所有接口返回结果,在req函数统一判断。用例中不再判断。

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)

说一下心得体会。

做demo和做真实项目完全是两回事。

快捷键是真好用,尤其是代码写多了之后。(虽然写的还不多,但快捷键是真滴)

性能很重要,该优化的要想办法及时优化,哪怕修改实现方式。

码代码前,就算封装一个函数,也要多思考设计,想清楚了再行动,不然挨个挨个重新改一遍真的五味杂陈。

编码效率>框架体验。这是加了用例执行进度1/100这种又去掉之后的感悟。没有必要纠结可有可无的细小体验添加冗余代码。

原文地址:https://www.cnblogs.com/df888/p/10912079.html

时间: 2024-10-27 06:16:16

接口自动化测试实践的相关文章

美团接口自动化测试实践

一.概述 1.1 接口自动化概述 众所周知,接口自动化测试有着如下特点: 低投入,高产出. 比较容易实现自动化. 和UI自动化测试相比更加稳定. 如何做好一个接口自动化测试项目呢? 我认为,一个"好的"自动化测试项目,需要从"时间"."人力"."收益"这三个方面出发,做好"取舍". 不能由于被测系统发生一些变更,就导致花费了几个小时的自动化脚本无法执行.同时,我们需要看到"收益",不能为

第9期《python3接口自动化测试》课程,6月29号开学!

2019年 第13期<python3接口自动化测试>课程,6月29号开学! 主讲老师:上海-悠悠 上课方式:QQ群视频在线教学 本期上课时间:6月29号-7月28号,每周六.周日晚上20:30-22:30 报名费:报名费1000一人(周期1个月) 联系QQ:283340479 个人成就: 1.个人博客,百度直接搜索:上海-悠悠博客 2.个人原创微信公众号:yoyoketang 3.已经在百度阅读上线的python四大名著,百度搜索:百度阅读,再搜索书名: <selenium webdri

APP接口自动化测试JAVA+TestNG(三)之HTTP接口测试实例

转载自:http://www.cnblogs.com/findyou/p/5388853.html 说明,本文为学习参考,将于一段时间后删除. 前言    前两篇普及相关基础知识后,本篇主要对举例对国家气象局接口自动化测试进行讲解(Get请求及结果断言),以达到自动化测试入门目的,除了前两篇的一些了解外,需要有一定的JAVA知识(HTTP相关). 目录 3.1 HTTP接口(GET)测试实例 3.1.1 待测接口说明 3.1.2 新建JAVA工程 1.工程目录说明 2.Common.java源码

零成本实现接口自动化测试 – Java+TestNG 测试Restful service

本文是转载Wade Xu的文章http://www.cnblogs.com/wade-xu/p/4229805.html 接口自动化测试 – Java+TestNG 测试 Restful Web Service 关键词:基于Rest的Web服务,接口自动化测试,数据驱动测试,测试Restful Web Service, 数据分离,Java+Maven+TestNG 本文主要介绍如何用Java针对Restful web service 做接口自动化测试(数据驱动),相比UI自动化,接口自动化稳定性

接口自动化测试方案PHP + mysql

接口测试在测试工作中是很常见的工作,但是在以往的接口测试工作中借助的一般是第三方插件.python开发的发送请求脚本.LR脚本.Jmeter脚本,之前也使用python开发了一套接口自动化测试系统,但那也是当时因为工作的需求而整理出来的,可能更加适合自己当时的工作,对于其他的小伙伴的帮助可能并不是很大,后面因为工作需要调整到了一个app的项目,在这个项目中我顿时发现之前的接口自动化系统作用不是很大,因为安全性的考虑服务端对接口进行了cookie.header等的验证,想想在现在的工作中这些情况也

接口自动化测试框架搭建 – Java+TestNG 测试Restful service

接口自动化测试 – Java+TestNG 测试 Restful Web Service 关键词:基于Rest的Web服务,接口自动化测试,数据驱动测试,测试Restful Web Service, 数据分离,Java+Maven+TestNG 本文主要介绍如何用Java针对Restful web service 做接口自动化测试(数据驱动),相比UI自动化,接口自动化稳定性可靠性高,实施难易程度低,做自动化性价比高.所用到的工具或类库有 TestNG, Apache POI, Jayway r

接口自动化测试--基础篇

点击标题下「蓝色微信名」可快速关注 坚持的是分享,搬运的是知识,图的是大家的进步,没有收费的培训,没有虚度的吹水,喜欢就关注.转发(免费帮助更多伙伴)等来交流,想了解的知识请留言,给你带来更多价值,是我们期待的方向,有更多兴趣的欢迎切磋,我们微信订阅号,联系方式如下: 更多书籍,敬请期待 上次分享了http协议后,很多朋友问,做接口自动化测试如何入门,今天小怪简单分享介绍下,1.我们需要的的基础知识,2.Fiddler接口测试演示,3.jmeter接口测演示,详细如下: 视频地址:https:/

【三】Jmeter接口自动化测试系列之Http接口自动化实战

作者:大虫 本文介绍 Jmeter 工具的 http 接口 自动化测试 实战! 为了通用性,就拿知乎 网站作为实战例子吧! 必备技能:http接口基础知识.抓包,本文不做详细介绍,不会的可以先百度恶补! 首先,我们把 知乎登录的包抓下来: 我们抓一下 获取 Jmeter 对应脚本如下: 获取发现栏目脚本: 使用正则表达提取器,提取栏目内容(what?不会正则表达式?找百度) 使用 foreach 控制器将提取结果合并到一个字符串 打印结果: 运行结果: 在进行http 接口测试的时候,通常需要注

接口自动化测试的&quot;开胃小菜&quot;---简单黑客攻击手段

Web应用系统的小安全漏洞及相应的攻击方式 接口自动化测试的"开胃小菜" 1   写作目的 本文讲述一个简单的利用WebAPI来进行一次基本没有破坏力的“黑客”行为. 主要目的如下: 了解什么叫安全漏洞 知道什么是api 了解一些获取api的工具 通过对API的认识了解白盒接口测试基本概念和技术 免责声明: 本文主要是以学习交流为目的,而且实验的对象也是通过搜索引擎随机选择的.不以搞破坏为目的,纯粹是以教学为目的,同时也警醒大伙重视基本的互联网安全.当然,本文会对关键字打个马赛克,防止