利用fitnesse实现api接口自动化测试
上午在园子里乱逛,看了不少小伙伴们分享的接口测试方面的知识,仔细想想,我做接口测试也有几个年头了,大家所叙述到的一些经验或多或少,我也曾遇到过,突然意识到知识的点滴积累是多么的重要,我记得我最早接触接口测试的时候,就是只在浏览器里人工测试单个接口的返回结果,后来用python的unittest自己写测试框架,和现在大多数小伙伴们的方法差不多,测试用例也是存放在excle表中,这对于单人测试来说都还ok,但是如果是多人协同测试时,问题就出来了,因为按目录存放在不同的excle表中的测试用例,维护起来比较麻烦,而且不便于多人查询或共同维护测试用例。所以之前的公司老大给我们推荐了一个工具——fitnesse,它是用wiki方式在界面上管理测试用例,驱动后台脚本进行测试,因为测试用例界面是个wiki地址,可以很方便的和大家一起协同工作,而且用例查询和维护起来都方便的多。
我在之前的公司用了将近一年这个工具,但是因为刚休完产假的自己工作状态非常不好,其实并没有在这方面很尽心,只到来了新公司后,才又一次重新学习使用起这个工具来,还是api接口测试,年前我从不同的角度分别写了几个不同的demo,虽然现在大多数用fitnesse的人都是用的slim引擎,但是因为java helloworld水平的我一直用的python,找不到合适的支持slim的python插件,所以还是用的fitnesse的fit引擎,用PyFIT支持起来。
对于api接口功能测试,我个人认为需要关注的有这几个方面:接口状态,响应时间,字段格式,返回数据,想起来之前面试阿里时,提到接口测试,他问了我很多http协议类的,具体问题记不清了,大概是几次握手交互那类的,额,不知道是不是关注点不同的缘故,他问得几个关于接口测试的问题我都没用过,其实到现在我还是有些疑惑的,不知道是他理解的接口测试和我理解的有偏差,不过也许是我涉猎的领域太窄,对于接口应该怎么充分测试我是比较怀疑了,也经常会在网上翻阅关于接口测试的文档,但是感觉收效甚微,嗯,对于未知领域的探索仍在继续,对于已知领域的小果子,拿出来和小伙伴一起分享下吧
所测接口:api接口,返回结果json格式
所用工具:fitnesse,fit引擎,python
第一种方式:
测试思想:在页面上初始化测试数据,将接口的返回结果按每个字段逐一填写期望结果,和接口的实际结果比较
测试数据准备:在界面上利用sql语句初始化测试数据,然后在测试用例页面included 该页面
测试用例:将json各个字段拆开填写到测试用例表格中,用ColumnFixture,测试用例格式如下
baseurl:接口基本不变的部分,这一部分可以在表格外参数化然后传值到表格里,account和password是接口的两个输入参数,带?标识的是要验证的结果,将json返回结果的每个字段都拆开填写在表格中。
后台脚本:
class LoginTest(ColumnFixture):_typeDict = {"description":"String","BaseUrl":"String","account":"String","password":"String","status":"Int","retMsg":"String","token":"String","uClen":"Int","uCuserId":"Int","uCamount":"String",}def __init__(self): ColumnFixture.__init__(self)self.account=''self.password=''self.BaseUrl=''self.jsonData='' self.ret='' def getRes(self): url=self.BaseUrl+"account="+self.account+"&password="+self.passwordtmp=res.fetch_res(url) result = json.loads(tmp)return resultdef retMsg(self):self.jsonData=self.getRes()self.ret=self.jsonData["ret"]result=str(self.jsonData["ret"])+self.jsonData["msg"]return result def status(self):url=self.BaseUrl+"account="+self.account+"&password="+self.passwordresult=res.fetch_status(url)return result def token(self):result=''if self.ret==1:result= self.jsonData["data"]["token"]return resultdef uClen(self):result=''if self.ret==1:result=len(self.jsonData["data"]["userCapital"])return resultdef uCuserId(self):result=''if self.ret==1: result=self.jsonData["data"]["userCapital"]["userId"]return resultdef uCamount(self):result=''if self.ret==1:result=str(self.jsonData["data"]["userCapital"]["amount"])return result
优点:测试脚本结构简单,测试用例格式清晰,缺点:如果接口返回层级或字段较多时,不便于测试用例维护,需要初始化测试数据并清除增加的数据,部分动态字段(比如creattime)无法准确校验
第二种方式:
测试思想:在已有数据库基础上,无需每次添加测试数据,在测试脚本中根据需求用sql语句检索出对应字段的数据,作为期望结果,和接口的实际结果比较
测试数据:已有数据库基础上
测试用例:
测试脚本部分示例:
def retMsg(self):if self.status==200: self.jsonData=self.getRes()isUserSql="SELECT * FROM hcm_user WHERE NAME LIKE \'"+self.account+"\' AND PASSWORD LIKE \'"+self.password+ "\'AND TYPE=0"self.isUser=db.queryDb(isUserSql) self.ret=self.jsonData["ret"]result=str(self.jsonData["ret"])+self.jsonData["msg"]return resultelse:return ''def securityStatusCheck(self):symbol="="list=['userId','userName','emailStatus','mobileStatus','realNameAuthStatus','autoTransfer','trusteeshipAccountStatus']dataJson=[]dataCase=[]if self.isUser:sql="SELECT a.id,a.`name`,IF(a.email!='',1,0),IF(a.`mobile`,1,0),b.`yeepay_account_status`,b.auto_transfer,b.`yeepay_account_status` FROM hcm_user a,hcm_user_auth b WHERE NAME LIKE '"+self.account+"' AND a.id=b.user_id" data=db.queryDb(sql)if data:for i in range (0,len(list)):dataCase.append(list[i]+symbol+str(data[0][i]))if self.ret==1:tmp=self.jsonData["data"]["securityStatus"]for i in range (0,len(list)):dataJson.append(list[i]+symbol+str(tmp[list[i]]))result=Check(dataJson, dataCase)return result
测试结果:
突然发现给自己写优缺点好二啊,反正就是上面两种都没有满足老大们的要求,他们希望我能写一个通用的框架,让没有任何编码能力的人也能进行接口测试,即只需要前台编写测试用例,不用管后台脚本就能进行测试,于是乎有了下面第三种方式
第三种方式:
测试思想:满足老大们的要求,不用编写任何脚本即可进行接口测试
测试数据:固定初始化好的数据库
测试用例:
其中,firsturl是被依赖的登录接口,url是所测接口,blackLIst是希望过滤de返回字段的黑名单(比如ordeId,每次都是变化的,无法准确校验,添加到黑名单中即可不对其校验),data是期望结果,因为所测接口需要先登录然后保持session,才能返回正常结果,所以此处采用的是fit的Actionfixture测试脚本示例:
from fit.Fixture import Fixture
import urllib2,cookielib,urllib
import module,json
import sys
reload(sys)
sys.setdefaultencoding('UTF-8')class ActionTest(Fixture):_typeDict = {}def __init__(self):#初始化参数Fixture.__init__(self)self.__firstUrl = '' #< Private attributes (Python convention).self.__url = ''self.__parameter = ''self.__blackList=''self.__data=''self.res=''self.status=''self.expectedList=''self.actualList=''self.test=''_typeDict["firstUrl"] = "String"def firstUrl(self, s):self.__firstUrl = s_typeDict["url"] = "String"def url(self, s):self.__url = s_typeDict["parameter"] = "Dict"def parameter(self, s):self.__parameter = s_typeDict["blackList"] = "List"def blackList(self, s):self.__blackList = s_typeDict["data"] = "String"def data(self, s):self.__data = s_typeDict["do"] = "Default" #< AUTO-DETECT: None = voiddef do(self):#访问接口并保存结果cookie=cookielib.CookieJar()opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))try:req=opener.open(self.__firstUrl)self.status=req.codeexcept urllib2.HTTPError, e:self.status= e.codeif self.status==200:for cj in cookie:if cj.name=='JSESSIONID':session= cj.valuereq=urllib2.Request(self.__url)data=urllib.urlencode(self.__parameter)try:tmp = opener.open(req,data)self.status=tmp.codeexcept urllib2.HTTPError, e:self.status=e.codeif self.status==200:self.res= tmp.read()else:self.res='{"status":"no 200"}'else:self.res='{"loginStatus":"no 200"}'_typeDict["status"] = "Int"def status(self):return self.status _typeDict["expect"] = "String"def expect(self):#调用module函数比较测试结果self.expectedList=[]self.actualList=[]module.resultList(self.__blackList,self.__data, self.res, self.expectedList, self.actualList)#比较后将结果存放到输出数组中 result=module.outPut(self.expectedList)#tmp=unicode(self.__data, 'utf-8')#return str(self.actualListreturn result_typeDict["actual"] = "String"def actual(self):#调用module函数比较测试结果result=module.outPut(self.actualList) return result
测试结果:
相关文章:
利用fitnesse实现api接口自动化测试
上午在园子里乱逛,看了不少小伙伴们分享的接口测试方面的知识,仔细想想,我做接口测试也有几个年头了,大家所叙述到的一些经验或多或少,我也曾遇到过,突然意识到知识的点滴积累是多么的重要,我记…...
【LeetCode】1154.一年中的第几天
题目描述: 给你一个字符串 date ,按 YYYY-MM-DD 格式表示一个 现行公元纪年法 日期。返回该日期是当年的第几天。 示例 1: 输入:date "2019-01-09" 输出:9 解释:给定日期是2019年的第九天。示…...
4.物联网射频识别,RFID开发【智能门禁项目】
补充:学习路径 一。项目介绍及需求分析 1.酒店智能门禁使用场景介绍 1.客人入住 客人在前台办理入住手续,前台管理员通过门禁管理系统为客户开一张门禁卡 客户持卡到相应客房,用IC 卡刷卡开门 客人过了入住时间后,卡自动失效&a…...
CompletableFuture 和 Future 的选择,以及CompletableFuture的用法
在 Java 编程中,异步编程是一种重要的技术,它允许你在执行长时间运行的任务时不会阻塞主线程。为了支持异步编程,Java 提供了 Future 和 CompletableFuture 这两个关键的类。在本文中,我们将比较它们的特点、优缺点以及使用场景。…...
美国第三大财产和意外险公司利宝保险集团利用 OpenText EnCase 取证收集技术控制法律风险和成本
美国第三大财产和意外险公司利宝保险集团利用 OpenText EnCase 取证收集技术控制法律风险和成本 利宝保险集团通过内部取证收集技术控制法律风险和成本。OpenText EnCase Information Assurance(以前称为 EnCase eDiscovery)使保险公司巨头能够自信高效地…...
打包报错JavaScript heap out of memory
npm run build 的时候出现了Reached heap limit Allocation failed - JavaScript heap out of memory,报错信息如下图所示。 奇怪的时候这个报错信息在本地不会出现,通过jekins在服务器打包部署的时候才会出现。于是进入服务器执行下面一句代码ÿ…...
Android Camera FW 里的requestId和frameId
安卓相机frameworks里面经常出现requestId和frameId,最近简单看了一下代码,发现相关流程还是很复杂的,总结来看requestId 就是上层(java)发送的repeating(capture)请求的id,是从0开始递增的。 这是CameraD…...
代理IP与Socks5代理在技术世界的多元应用
在数字化时代,网络工程师的任务不仅是维护网络的稳定性,还需要应对各种技术挑战。代理IP与Socks5代理作为技术工具箱中的两把利器,在跨界电商、爬虫、出海业务、网络安全和游戏领域中发挥了关键作用。本文将深入探讨这两项技术在不同领域的多…...
计算机专业毕业设计项目推荐12-志愿者管理系统(Spring+Js+Mysql)
志愿者管理系统(SpringJsMysql) **介绍****各部分模块实现** 介绍 本系列(后期可能博主会统一为专栏)博文献给即将毕业的计算机专业同学们,因为博主自身本科和硕士也是科班出生,所以也比较了解计算机专业的毕业设计流程以及模式,在编写的过程…...
苹果文件传到mac电脑用什么软件?
在数字化时代,文件传输已经成为我们日常生活中不可或缺的一部分。然而,苹果用户在将手机文件传输到电脑时,往往会面临一些困扰。曾经的“文件传输助手”并不能完全满足用户的需求。于是,很多人开始寻找更便捷的解决方案。在本文中…...
深入理解Docker:简化部署与管理的利器
文章目录 引言Docker简介Docker的背景和发展Docker的优势和特点 Docker的基本概念和架构镜像(Image)容器(Container)仓库(Repository)Docker架构 Docker的常用命令和操作Docker的安装和配置Docker镜像的管理…...
软考对找工作有用吗?
软考是指软件技术专业资格考试,是由中国人力资源和社会保障部主管的一项国家级考试。软考的目标是评估和认证软件技术人员的专业能力,提高软件行业的整体素质和竞争力。那么,软考对找工作有用吗?本文将从以下几个方面进行分析。 首…...
Android系统启动之init进程启动+Zygote进程启动分析
一、基础概念理解 init进程 Android系统所有进程的祖先,是Android系统内核初始化完毕后,进入用户空间启动的第一个进程。 Android虚拟机 Dalvik虚拟机是谷歌自己设计的用于Android平台的虚拟机。Android4.4同时提供了Dalvik和ART虚拟机。Android5.0以后…...
微信这样的加人方式,既安全又解放双手
在当今竞争激烈的市场环境下,如何高效地管理和运营私域流量成为企业发展的关键。 1.批量自动化加好友的优势 (1)提高效率:批量自动化添加好友功能可以帮助企业添加大量潜在客户或目标客户。相比手动逐个添加好友,自动…...
CVE-2023-5129:libwebp开源库10分漏洞
谷歌为libwebp漏洞分配新的CVE编号,CVSS评分10分。 Libwebp是一个用于处理WebP格式图像编解码的开源库。9月6日,苹果公司安全工程和架构(SEAR)部门和加拿大多伦多大学研究人员在libwebp库中发现了一个0 day漏洞,随后&…...
从零开始的C++(六)
1.类和对象补充: 静态成员,有静态成员函数和静态成员变量,特点是不为类的某个对象所有,而是为同类所有对象共有。因为是为同类对象共同拥有,所以计算对象的大小的时忽略静态成员。因为静态成员是放在静态区࿰…...
leetcode 518. 零钱兑换 II、377. 组合总和 Ⅳ
518. 零钱兑换 II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 …...
【网络安全 --- kali2022安装】kali2022 超详细的安装教程(提供镜像)
如果你还没有安装vmware 虚拟机,请参考下面博客安装 【网络安全 --- 工具安装】VMware 16.0 详细安装过程(提供资源)-CSDN博客【网络安全 --- 工具安装】VMware 16.0 详细安装过程(提供资源)https://blog.csdn.net/m0…...
网络安全(黑客)——自学笔记
前言: 想自学网络安全(黑客技术)首先你得了解什么是网络安全!什么是黑客 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“…...
【C++】List -- 详解
一、list的介绍及使用 https://cplusplus.com/reference/list/list/?kwlist list 是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。 list 的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中&…...
浅谈.net 垃圾回收机制(1)
大家都知道.net程序创建对象后没法写代码销毁对象,它有它自己的处理机制,今天来大概说说它的原理,探讨下它是如何管理对象即管理内存的 在程序里使用new 关键字实例化一个对象 如果这个对象类型是引用类型则在堆上分配然后由GC管理 new 操作…...
超大视频如何优雅切片
背景 有一次录屏产生了一个大小为33G的文件, 我想把他上传到B站, 但是B站最大只支持4G. 无法上传, 因此做了一个简单的探索. 质疑与思考 a. 有没有一个工具或一个程序协助我做分片呢? 尝试 a. 必剪 > 有大小限制, 添加素材加不进去(而且报错信息也提示的不对) b. PR &…...
计算机竞赛 题目:基于深度学习卷积神经网络的花卉识别 - 深度学习 机器视觉
文章目录 0 前言1 项目背景2 花卉识别的基本原理3 算法实现3.1 预处理3.2 特征提取和选择3.3 分类器设计和决策3.4 卷积神经网络基本原理 4 算法实现4.1 花卉图像数据4.2 模块组成 5 项目执行结果6 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 基…...
Spring总结的question
Spring 一. 控制反转(IoC) 1.手动 使用了Spring的Configuration和Bean注解来明确指定了哪些类需要被纳入容器的管理。在AppConfig配置类中,通过Bean注解创建了Service和Controller的实例,Spring会自动将这些实例纳入容器的管理,并处理它们…...
LVS和keepalived
Keepalived及其工作原理 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案,可以解决静态路由出现的单点故障问题。 在一个LVS服务集群中通常有主服务器(MASTER)和备份服务器(BACKUP)两种角色的服务器&#x…...
2023年腾讯云优惠券(代金券)无门槛领取方法汇总
腾讯云作为国内知名的云计算服务提供商,为了吸引用户,腾讯云经常推出各种优惠活动,其中包括优惠券的免费发放。通过使用优惠券,可以享受到更多的折扣和优惠,节省成本,获得更好的用户体验。那么,…...
linux scsi命令读取文件
SCSI Read(10)是一种用于从SCSI设备读取数据的命令。下面是一个简单的示例代码,演示如何使用SCSI Read(10)命令来读取指定大小的文件: #include <stdio.h> #include <stdlib.h> #include <string.h>#define READ_CAPACITY_CMD 0x2…...
c#设计模式-行为型模式 之 策略模式
🚀简介 🐤作为一个开发人员,开发需要选择一款开发工具,如在编写C#时,我们可以选择VisualStudio进行开发,也可以使用Rider 进行开发。 🐳该模式定义了一系列算法,并将每个算法封装起来…...
【拿完年终奖后】想要转行网络安全,一定不要错过这个时间段。
网络安全,作为当下互联网行业中较为热门的岗位,薪资可观、人才需求量大,作为转行必考虑。 在这里奉劝所有零基础想转行(入门) 网络安全的朋友们 在转行之前,一定要对网络安全行业做一个大概了解…...
day10_复习_数组_方法
非常重要的: 方法设计(参数,返回值,调用) 数组也重要,但是后续很少用! 是因为后期有更简单的【集合】,重要在于是一种思想,也是一种代码逻辑 关于数组: 声明创建取值,存值遍历面试|算法 --> 排序内存图(堆,栈,引用) 今天 数组工具类:Arrays数组扩容(拷…...
网站建设中网站功能描述书功能/全网万能搜索引擎
店铺编辑 首先获取店铺的信息,然后在此基础上进行改动 编写店铺查询queryByShopId(long shopId) 因为在查询店铺时,shop表中只含有 这些PersonInfo,Area,ShopCategory的id,但是需要显示的是所有者的名字,区…...
阿里云轻云服务器可以放多个网站啊怎么做/深圳竞价排名网络推广
下面介绍一下 Yii2.0 对数据库 一些简单的操作 User::find()->all(); 此方法返回所有数据;User::find()->one(); 此方法返回一条数据;User::find()->limit(3) 此方法返回3条数据User::find()->count(); 此方法返回记录的数…...
python做网站用什么框架/竞价网络推广培训
RFID防碰撞算法学习 引用文章地址 RFID中的碰撞问题主要分为两类:一是阅读器碰撞问题,它产生于同一个物理区域内存在多个不同的阅读器,它们以同一频率同时与区域内的标签通信而引起的冲突。另一类是标签碰撞问题,如过标签同事处于…...
济南 论坛网站建设/推广形式
Activity的构成并不是一个Activity对象再加上一个布局那么简单 再Activity和开发人员设置的视图之间还隔着两层。实际上视图会被设置给一个Window 类,这个Window中含有一个DecorView,这个DecorView才是窗口的顶级视图。 开发人员设置的布局会被设置到这…...
淮安做网站就找卓越凯欣/济南优化seo公司
在上一节中,我们基本了解到了Linux系统中的文本编辑Vim,也知道如何去使用vim,其实这个时候我们已经可以去使用vim了,但是如果我们想要提高使用vim的效率,还需要掌握vim的几组常用命令。 一、插入命令 插入命令在上一…...
石家庄网站优化/近期国际新闻热点大事件
行动源于两点:对快乐的追求和对痛苦的逃避。而逃离恐惧与痛苦的力量更大。一个人不能化心动为行动只有两个原因,要么是对快乐的渴望不够强烈,要么是对痛苦的恐惧滋味儿尚未尝够。你之所以还仅仅只是在想成功,是因为现况还没把你逼…...