当前市面上存在的接口测试工具已经很是多,常见的如Postman
、JMeter
、RobotFramework
等,相信大多数测试人员都有使用过,至少从接触到的大多数简历的描述上看是这样的。除了这些成熟的工具,也有不少有必定技术能力的测试(开发)人员自行开发了一些接口测试框架,质量也是良莠不齐。python
可是,当我打算在项目组中推行接口自动化测试时,搜罗了一圈,也没有找到一款特别满意的工具或框架,老是与理想中的构想存在必定的差距。git
那么理想中的接口自动化测试框架应该是怎样的呢?github
测试工具(框架)脱离业务使用场景都是耍流氓!因此咱们不妨先来看下平常工做中的一些常见场景。数据库
能够看到,以上罗列的场景你们应该都很熟悉,这都是咱们在平常工做中常常须要去作的事情。可是在没有一款合适工具的状况下,效率每每十分低下,或者就是某些重要工做压根就没有开展,例如接口回归测试、线上接口监控等。编程
先说下最简单的手工调用接口测试。可能有人会说,Postman
就能够知足需求啊。的确,Postman
做为一款通用的接口测试工具,它能够构造接口请求,查看接口响应,从这个层面上来讲,它是知足了接口测试的功能需求。可是在具体的项目中,使用Postman
并非那么高效。json
不妨举个最多见的例子。网络
某个接口的请求参数很是多,而且接口请求要求有
MD5
签名校验;签名的方式为在Headers中包含一个sign
参数,该参数值经过对URL
、Method
、Body
的拼接字符串进行MD5
计算后获得。session
回想下咱们要对这个接口进行测试时是怎么作的。首先,咱们须要先参照接口文档的描述,手工填写完全部接口参数;而后,按照签名校验方式,对全部参数值进行拼接获得一个字符串,在另外一个MD5计算工具计算获得其MD5值,将签名值填入sign
参数;最后,才是发起接口请求,查看接口响应,并人工检测响应是否正常。最坑爹的是,咱们每次须要调用这个接口的时候,以上工做就得从新来一遍。这样的实际结果是,面对参数较多或者须要签名验证的接口时,测试人员可能会选择忽略不进行接口测试。数据结构
除了单个接口的调用,不少时候咱们也须要组合多个接口进行调用。例如测试人员在测试物流系统时,常常须要一个特定组合条件下生成的订单号。而因为订单号关联的业务较多,很难直接在数据库中生成,所以当前业务测试人员广泛采起的作法,就是每次须要订单号时模拟下单流程,顺序调用多个相应的接口来生成须要的订单号。能够想象,在手工调用单个接口都如此麻烦的状况下,每次都要手工调用多个接口会有多么的费时费力。并发
再说下接口自动化调用测试。这一起大多接口测试框架都支持,广泛的作法就是经过代码编写接口测试用例,或者采用数据驱动的方式,而后在支持命令行(CLI)调用的状况下,就能够结合Jenkins
或者crontab
实现持续集成,或者定时接口监控的功能。
思路是没有问题的,问题在于实际项目中的推进落实状况。要说自动化测试用例最靠谱的维护方式,仍是直接经过代码编写测试用例,可靠且不失灵活性,这也是不少经历过惨痛教训的老手的感悟,甚至网络上还出现了一些反测试框架的言论。但问题在于项目中的测试人员并非都会写代码,也不是对其强制要求就能立刻学会的。这种状况下,要想在具体项目中推进接口自动化测试就很难,就算我能够帮忙写一部分,可是不少时候接口测试用例也是要结合业务逻辑场景的,我也的确是无法在这方面投入太多时间,毕竟对接的项目实在太多。因此也是基于这类缘由,不少测试框架提倡采用数据驱动的方式,将业务测试用例和执行代码分离。不过因为不少时候业务场景比较复杂,大多数框架测试用例模板引擎的表达能力不足,很难采用简洁的方式对测试场景进行描述,从而也无法很好地获得推广使用。
能够列举的问题还有不少,这些也的确都是在互联网企业的平常测试工做中真实存在的痛点。
基于以上背景,我产生了开发ApiTestEngine
的想法。
对于ApiTestEngine
的定位,与其说它是一个工具或框架,它更多的应该是一套接口自动化测试的最佳工程实践,而简洁优雅实用
应该是它最核心的特色。
固然,每位工程师对最佳工程实践
的理念或多或少都会存在一些差别,也但愿你们能多多交流,在思惟的碰撞中共同进步。
ApiTestEngine
的核心特性概述以下:
YAML
支持API接口的多种请求方法,包括 GET/POST/HEAD/PUT/DELETE 等
我的偏好,编程语言选择Python。而采用Python实现HTTP请求,最好的方式就是采用Requests
库了,简洁优雅,功能强大。
测试用例与代码分离,测试用例维护方式简洁优雅,支持
YAML
要实现测试用例与代码的分离,最好的作法就是作一个测试用例加载引擎和一个测试用例执行引擎,这也是以前在作AppiumBooster
框架的时候总结出来的最优雅的实现方式。固然,这里须要事先对测试用例制定一个标准的数据结构规范,做为测试用例加载引擎和测试用例执行引擎的桥梁。
须要说明的是,测试用例数据结构必须包含接口测试用例完备的信息要素,包括接口请求的信息内容(URL、Headers、Method等参数),以及预期的接口请求响应结果(StatusCode、ResponseHeaders、ResponseContent)。
这样作的好处在于,无论测试用例采用什么形式进行描述(YAML
、JSON、CSV、Excel、XML等),也无论测试用例是否采用了业务分层的组织思想,只要在测试用例加载引擎中实现对应的转换器,均可以将业务测试用例转换为标准的测试用例数据结构。而对于测试用例执行引擎而言,它无需关注测试用例的具体描述形式,只须要从标准的测试用例数据结构中获取到测试用例信息要素,包括接口请求信息和预期接口响应信息,而后构造并发起HTTP请求,再将HTTP请求的响应结果与预期结果进行对比判断便可。
至于为何明确说明支持YAML
,这是由于我的认为这是最佳的测试用例描述方式,表达简洁不累赘,同时也能包含很是丰富的信息。固然,这只是我的喜爱,若是喜欢采用别的方式,只须要扩展实现对应的转换器便可。
测试用例描述方式具备表现力,可采用简洁的方式描述输入参数和预期输出结果
测试用例与框架代码分离之后,对业务逻辑测试场景的描述重任就落在测试用例上了。好比咱们选择采用YAML
来描述测试用例,那么咱们就应该能在YAML
中描述各类复杂的业务场景。
那么怎么理解这个“表现力”呢?
简单的参数值传参应该都容易理解,咱们举几个相对复杂但又比较常见的例子。
X-ATE-V
头域,而且须要判断该值是否大于100;能够看出,以上几个例子都是无法直接在测试用例里面描述参数值的。若是是采用Python脚原本编写测试用例还好解决,只须要经过Python函数实现便可。可是如今测试用例和框架代码分离了,咱们无法在YAML
里面执行Python函数,这该怎么办呢?
答案就是,定义函数转义符,实现自定义模板。
这种作法其实也不难理解,也算是模板语言通用的方式。例如,咱们将${}
定义为转义符,那么在{}
内的内容就再也不当作是普通的字符串,而应该转义为变量值,或者执行函数获得实际结果。固然,这个须要咱们在测试用例执行引擎进行适配实现,最简单方式就是提取出${}
中的字符串,经过eval
计算获得表达式的值。若是要实现更复杂的功能,咱们也能够将接口测试中经常使用的一些功能封装为一套关键字,而后在编写测试用例的时候使用这些关键字。
接口测试用例具备可复用性,便于建立复杂测试场景
不少状况下,系统的接口都是有业务逻辑关联的。例如,要请求调用登陆接口,须要先请求获取验证码的接口,而后在登陆请求中带上获取到的验证码;而要请求数据查询的接口,又要在请求参数中包含登陆接口返回的session值。这个时候,咱们若是针对每个要测的业务逻辑,都单独描述要请求的接口,那么就会形成大量的重复描述,测试用例的维护也十分臃肿。
比较好的作法是,将每个接口调用单独封装为一条测试用例,而后在描述业务测试场景时,选择对应的接口,按照顺序拼接为业务场景测试用例,就像搭积木通常。若是你以前读过AppiumBooster
的介绍,应该还会联想到,咱们能够将经常使用的功能组成模块用例集,而后就能够在更高的层面对模块用例集进行组装,实现更复杂的测试场景。
不过,这里有一个很是关键的问题须要解决,就是如何在接口测试用例以前传参的问题。其实实现起来也不复杂,咱们能够在接口请求响应结果中指定一个变量名,而后将接口返回关键值提取出来后赋值给那个变量;而后在其它接口请求参数中,传入这个${变量名}
便可。
测试执行方式简单灵活,支持单接口调用测试、批量接口调用测试、定时任务执行测试
经过背景中的例子能够看出,须要使用接口测试工具的场景不少,除了定时地对全部接口进行自动化测试检测外,不少时候在手工测试的时候也须要采用接口测试工具进行辅助,也就是半手工+半自动化
的模式。
而业务测试人员在使用测试工具的时候,遇到的最大问题在于除了须要关注业务功能自己,还须要花费不少时间去处理技术实现细节上的东西,例如签名校验这类状况,并且每每后者在重复操做中占用的时间更多。
这个问题的确是无法避免的,毕竟不一样系统的接口千差万别,不可能存在一款工具能够自动处理全部状况。可是咱们能够尝试将接口的技术细节实现和业务参数进行拆分,让业务测试人员只须要关注业务参数部分。
具体地,咱们能够针对每个接口配置一个模板,将其中与业务功能无关的参数以及技术细节封装起来,例如签名校验、时间戳、随机值等,而与业务功能相关的参数配置为可传参的模式。
这样作的好处在于,与业务功能无关的参数以及技术细节咱们只须要封装配置一次,并且这个工做能够由开发人员或者测试开发人员来实现,减轻业务测试人员的压力;接口模板配置好后,测试人员只须要关注与业务相关的参数便可,结合业务测试用例,就能够在接口模板的基础上很方便地配置生成多个接口测试用例。
测试结果统计报告简洁清晰,附带详尽日志记录,包括接口请求耗时、请求响应数据等
测试结果统计报告,应该遵循简洁而不简单的原则。“简洁”,是由于大多数时候咱们只须要在最短的时间内判断全部接口是否运行正常便可。而“不简单”,是由于当存在执行失败的测试用例时,咱们指望能得到接口测试时尽量详细的数据,包括测试时间、请求参数、响应内容、接口响应耗时等。
以前在读locust
源码时,其对HTTP
客户端的封装方式给我留下了深入的印象。它采用的作法是,继承requests.Session
类,在子类HttpSession
中重写覆盖了request
方法,而后在request
方法中对requests.Session.request
进行了一层封装。
request_meta = {}
# set up pre_request hook for attaching meta data to the request object
request_meta["method"] = method
request_meta["start_time"] = time.time()
response = self._send_request_safe_mode(method, url, **kwargs)
# record the consumed time
request_meta["response_time"] = int((time.time() - request_meta["start_time"]) * 1000)
request_meta["content_size"] = int(response.headers.get("content-length") or 0)复制代码
而HttpLocust
的每个虚拟用户(client)都是一个HttpSession
实例,这样每次在执行HTTP
请求的时候,既可充分利用Requests
库的强大功能,同时也能将请求的响应时间、响应体大小等原始性能数据进行保存,实现可谓十分优雅。
受到该处启发,要保存接口的详细请求响应数据也可采用一样的方式。例如,要保存Response
的Headers
、Body
只须要增长以下两行代码:
request_meta["response_headers"] = response.headers
request_meta["response_content"] = response.content复制代码
身兼多职,同时实现接口管理、接口自动化测试、接口性能测试(结合Locust)
其实像接口性能测试这样的需求,不该该算到接口自动化测试框架的职责范围以内。可是在实际项目中需求就是这样,又要作接口自动化测试,又要作接口性能测试,并且还不想同时维护两套代码。
多亏有了locust
性能测试框架,接口自动化和性能测试脚本还真能合二为一。
前面也讲了,HttpLocust
的每个虚拟用户(client)都是一个HttpSession
实例,而HttpSession
又继承自requests.Session
类,因此HttpLocust
的每个虚拟用户(client)也是requests.Session
类的实例。
一样的,咱们在用Requests
库作接口测试时,请求客户端其实也是requests.Session
类的实例,只是咱们一般用的是requests
的简化用法。
如下两种用法是等价的。
resp = requests.get('http://debugtalk.com')
# 等价于
client = requests.Session()
resp = client.get('http://debugtalk.com')复制代码
有了这一层关系之后,要在接口自动化测试和性能测试之间切换就很容易了。在接口测试框架内,能够经过以下方式初始化HTTP
客户端。
def __init__(self, origin, kwargs, http_client_session=None):
self.http_client_session = http_client_session or requests.Session()复制代码
默认状况下,http_client_session
是requests.Session
的实例,用于进行接口测试;当须要进行性能测试时,只须要传入locust
的HttpSession
实例便可。
具备可扩展性,便于扩展实现Web平台化
当要将测试平台推广至更广阔的用户群体(例如产品经理、运营人员)时,对框架实现Web化就在所不免了。在Web平台上查看接口测试用例运行状况、对接口模块进行配置、对接口测试用例进行管理,的确会便捷不少。
不过对于接口测试框架来讲,Web平台
只能算做锦上添花的功能。咱们在初期能够优先实现命令行(CLI)调用方式,规范好数据存储结构,后期再结合Web框架(如Flask)增长实现Web平台功能。
以上即是我对ApiTestEngine
特性的详细介绍,也算是我我的对接口自动化测试最佳工程实践
的理念阐述。
当前,ApiTestEngine
还处于开发过程当中,代码也开源托管在GitHub上,欢迎Star
关注。
GitHub项目地址:github.com/debugtalk/A…