api自动化之:python3实现fiddler爬虫转化为httprunner自动化case

需求背景

传统测试开发的接口自动化工程模型

一般掌握python的测试开发人员都喜欢使用python创建一套自动化工程。其中,大部分人应该都接触过一套架构模式:
语言:python(2/3)
库:requests,unittest,htmltestrunner
以requests实现http请求,unittest实现断言及报告,htmltestrunner实现html测试报告的生成。这是三大主要核心结构。当然还有比如用mvc框架集自动化执行和测试报告预览的平台,又或者是用邮件库实现的测试报告发送等各种形式。

为什么由传统代码工程改为工具平台

测试的入门门槛是比较低的,可能开发人员必须是精通某一门语言,多种技术。而测试就存在不懂任何语言,不懂任何技术的情况,并且即便是技术流,那也未必恰好都会使用python,可能有些人更喜欢java,或者是其它语言。还有就是每个人都有一定的发展过程,总会有他的技术薄弱的阶段。另外,一个企业专门组织测试开发团队是比较消耗成本的,而自动化开发的工作放在个别人的手上就很难实现同步。所以开发测试平台是一种人人都能参与自动化开发的方式。

我们自动化平台的结构

我们是基于httprunner框架进行本地化改造实现的平台。但是核心功能没有做太多变化,只是做了很多加法。
httpruuner的实现是使用python3的django框架完成的,有web交互页面,mysql数据库。其中,requests和unittest还是他的主要核心。自动化测试用例的实现,要求测试人员掌握http协议,把请求的必要信息填入用例内,加上必要的响应断言,只要做好数据回收,保证用例可以反复执行就好。其中有些需要计算,遍历,筛选,随机等无法写死的参数,则必须使用python函数进行实现,在用例中调用函数即可。所以测试开发的工作在这个时候就是负责写这些工具化函数。

演变1:swagger爬虫

这一部分的实现我以后有机会会分享出来。swagger接口文档是放在源码上的框架,我通过爬取接口文档的api,把它转化成自动化平台用例的数据格式,插入到mysql中,就实现了代替手工去创建case的方式。测试人员只需要把必要的参数维护进去就够了,这样也能避免测试人员手工创建case的时候经常手误犯错。

演变2:fiddler爬虫

实现第一步之后,测试人员需要通过手工操作,根据fiddler的抓包结果去提取数据维护进swagger抓下来的无数据用例内。那么显然现在的主要工作就是找到在fiddler里想要抓的接口,如果是webform或query这种表单,就需要一个字段一个字段的复制,还是有些麻烦的。所以心生一计----对fiddler进行爬虫。

实现思路

fiddler是应用于windows平台一款http协议抓包工具。作为一个中间代理,可以抓到手机或者电脑上发出的http请求,从而进行分析。如果看到这里不知道fiddler是做什么用的,建议去网上搜索一下它的使用方式,这里就不做关于它的分享了。比如我打开fiddler,在要实现自动化的业务上进行一番操作,同时注意抓包结果,你至少要知道哪些是你需要的。这个时候可以删除不需要实现自动化的,重复的接口,只保留想要实现自动化的抓包记录。全选后,右键-sava-selected session-as text.也就是把抓包的结果储存到本地的一个txt文档里。
image.png

(为了保护我司域名,用张表情遮挡一下host)
保存下来之后见下图:


image.png

大概看一下:
1、请求方法

2、请求头内的:授权口令
3、入参
4、响应
这是几个必要参数。响应通常我们校验code是不是200就可以了。所以对于码农来说,就是把这个txt文件想要的东西爬出来做好归类,再以测试平台内数据存储需要的格式塞到库里就OK了。

上菜

def analysisFiddler(headers):
    f = open(r"D:\AutoBugrate\AuToBugrate\1616_Full.txt",encoding="utf-8").read()
    reqList = f.split("------------------------------------------------------------------")
    newReqList = []

    for i in reqList:
        a = i.split("\n")
        while "" in (a):
            a.remove("")
        if a != []:
            newReqList.append(a)
    nameList = []
    fullUrlList = []
    methodList = []
    for i in newReqList:
        host = i[1].split(": ")[1]
        nameList.append(i[0].split(" ")[1].split(host)[1].replace("/","_"))
        fullUrlList.append(i[0].split(" ")[1])
        methodList.append(i[0].split(" ")[0])
    # print(nameList)
    # print(fullUrlList)

    publicBaseReqList = [{'test':
               {'skipIf': {},
                 'request': {'url': url,
                             'times': '1',
                             'sleep': '0',
                             'method': method,
                             'headers': headers},
                 'rollback': {},
                 'name': name,
                 'validate': [{'comparator': 'equals',
                               'check': 'content.code',
                               'expected': 200}]}}
                for url,method,name in zip(fullUrlList,methodList,nameList)] #定义一个通用的request用于sql

    # print(publicBaseReqList)

    for i,l in zip(newReqList,publicBaseReqList):
        i.pop()
        for j in i:
            for k in (j.split(" ")):
                if "{" in k:
                    l['test']['request']['json'] = eval(k)


    # print(publicBaseReqList)


    create_time = update_time = dayTime_get()
    caseType = '1' #1表示用例 2表示配置
    belong_project = '外拓项目'
    include = "[{'config': ['2980', '外拓配置-ST']}]"
    author='julian'
    belong_module_id = '156'

    conn = pymysql.connect(
    host='192.168.x.xx',
    port=3306,
    user='root',
    password='xxxxxx',
    db='autobots',
    cursorclass=pymysql.cursors.DictCursor,
    charset='utf8'
    )
    cur = conn.cursor()

    for name,request in zip(nameList,publicBaseReqList):
        # if (not bool(re.search('[a-zA-Z]',name))) and (name not in popNameList):#v1.1增加
        insertCaseSql = '''INSERT INTO `autobots`.`testcaseinfo` (
                        `id`,`create_time`,`update_time`,
                        `type`,`name`,`belong_project`,
                        `include`,`author`,`request`,`belong_module_id`)
                        VALUES(NULL,"%s","%s","%s","%s","%s","%s","%s","%s","%s")'''%(
            create_time,update_time,caseType,name,belong_project,include,author,request,belong_module_id)
        print(insertCaseSql)
        print('-'*200)

        cur.execute(insertCaseSql)
        conn.commit()
        time.sleep(1)

    cur.close()
    conn.close()

analysisFiddler(headers={'Authorization': 'Bearer $Authorization'})

大概介绍一下代码思路:
1、首先读取fiddler的文档路径
2、文档内一一排减号作为两次不同接口请求的分割线,所以我们使用它先做一次粗分割
3、然后再利用换行符做进一步的分割,并去掉空行
4、先提取每个请求的第一行,先抽取出host,再以host为分割标记,截取url,把url中的路径标记"/"替换成"-",因为在平台内,用例名字里包含正斜杠会被解析成路径,从而报用例找不到。替换完后,作为用例名字,存好放在列表内。同理,把url提炼出来,把请求方法也提炼出来。
5、下一步publicBaseReqList这个字典,就是测试平台的数据库内存储的测试用例的数据结构。skipif是跳过的条件,这里空着即可。request里的内容是主要区别,包含url,重试次数,睡眠时间,请求方法,请求头。rollback是回滚条件,也空着。name就是用例名称,validate里面的内容就是断言。其中我把请求头放在形参内,因为仅用到一个身份口令,这一批接口是一致的。后面就是做一次for循环,使用抓出来的url,method,name三个列表,把数据分别组装进去。每一个case都有一套数据结构。
6、有了基础的请求结构,还缺最主要的,body。由于我抓的这批接口都是application/json格式,所以我直接用"{"去找到这个json串。为了避免最后面的响应串干扰,先把它pop掉。
7、再往下就是插库了,把数据库内必要的参数补全,比如创建人,创建时间,更新时间,用例所属的工程,模块,以及前提条件(include),这里就包含一些基础的登录操作,提供token等信息。
8、最后就是愉快的执行。

image.png

它确实与swagger爬出来的不一样,因为名字都是按照接口路径拼的,swagger的是有中文名字的,不过这个不重要。看看里面
请求:


image.png

断言:


image.png

总体执行一下:


image.png

全部通过。
但是不要高兴的太早,因为我知道我抓的这批接口都只是查询类的。如果有一些增删改之类的,应该需要做一些微调,局部参数化。但是这已经很节省时间了对不对,因为脚本不是只使用一次的。后续还会做进一步的优化,让它适应各种各样的类型。
比如请求头更丰富多变,用什么样的方法过滤form,query的请求格式,都需要兼容。
不过,掌握http协议,掌握python爬虫和正则,自然心中有码,逢山开路遇水搭桥呗。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容