You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

127 lines
11 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 05 | 案例测试框架如何才能支持RESTful风格的接口
你好,我是陈磊。
在前面的课程中,我们一起学习了如何把流程化的测试脚本,一步一步抽象成你自己的测试框架。无论你用的是什么编程语言,封装和抽象自己的测试框架都会让你的接口测试任务事半功倍。
我相信你在平时生活或工作中一定会接触到各式各样的软件系统而现在的软件系统和5年前相比最大差别就在于结构不同。
在我读大学的时候绝大部分系统还都是用一个Tomcat来搞定的但现在的系统更加复杂它们已经无法只用一个Web中间件独立对外提供服务它们之间都也是通过相互调用来完成业务逻辑的这里面既包含了服务端和服务端的调用也包含了前端和服务端的调用这就催生了RESTful风格的HTTP接口。
所以这节课我就来和你讲讲如何让你的测试框架完美支持RESTful风格的接口测试。这里我希望你能不断强化封装测试框架的三个流程不断为自己的接口测试框架添砖加瓦。
不过我不会将RESTful的规则一条一条念给你听我想让你知道的重点是作为测试工程师你要学会从测试工程师的角度观察RESTful接口要学会怎么分析和验证这类接口这也是今天我们今天这节课的主要内容。
## RESTful风格接口关我什么事
看到这里,你是不是一脸困惑:**RESTful是一个接口的封装风格和我们测试人员有什么关系呢**
要想理解它和我们测试工程师的关系你就要先知道RESTful风格的接口到底有什么好。
如果你用螺丝、钉子和板材等一系列原材料组装过家具,那么你肯定见到过各种千奇百怪的螺丝,比如一字的、十字的、三角形的、六角形的和海星形的等等,为了加固这些各式各样的螺丝,你就要准备各式各样的螺丝刀,因此,你的工具箱就会被不同规格和大小的螺丝刀填满。
不知道你是不是也和我一样,面对塞满螺丝刀的、乱七八糟的工具箱,心里非常急躁。但后来我在宜家看到一款螺丝刀,它只有一个刀柄,但给你提供了一整套各种形状、各种大小的螺丝刀刀头。
这样你在使用时,只要根据螺丝规格的不同,选择替换同形状的刀头就可以了;与此同时,它们放在工具箱里面又会显得很整齐,而不会七零八落。而且,如果你后续需要使用其它特殊形状的螺丝刀,你只要买和刀柄连接口一样的刀头就可以了,而不用再买一个完整的螺丝刀了。
如果你理解了上面这个场景也就能很好地理解RESTful风格的接口了。**它主要就是一组设计原则和约束条件本质上就是让消费者依据URI就可以找到资源并通过简单的服务输入输出完成服务的交互。**
它所约束的每一个URI都是独一无二的一个资源通过HTTP的方法进行资源操作实现表现层的状态转化。这就和螺丝刀刀头一样待解决的问题就像螺丝每一个接口只面向一种特定的资源而不需要关心其他接口的处理方式这样你就能够一目了然地知道该用哪种螺丝刀头拧哪种螺丝了这就降低了接口开发的复杂度。
软件开发人员只要遵循RESTful的实践标准按照一定的内部定义开发外接口就会形成类似螺丝刀刀头一样轻便的接口对外提供服务。现在的很多项目无论是服务端和服务端的调用还是前端和服务端的调用都采用了这一种方式来设计接口。
对于我们测试工程师来说RESTful风格的接口还是之前的访问模式它同样是一种HTTP协议的接口同样可以使用我们上节课一起封装的框架完成接口测试的任务。
但是它和我们之前讲过的HTTP协议的接口测试还是有一些区别这些区别导致了你现在的框架还需要做一些修改这样才能让它支持RESTful风格的接口测试。
## 让你的框架可以测试一个RESTful风格接口
现在你知道RESTful接口和你的接口测试有很大关系了那么RESTful接口的测试和原始的HTTP协议接口的测试又有什么区别呢
这里面有两部分需要你特别关注:**数据交换的承载方式和操作方式**。
我先说说数据交换的承载方式RESTful风格的接口主要是以JSON格式来进行数据交换如果你还记得我之前提过的“Battle”这个系统你可以回到[03](https://time.geekbang.org/column/article/193912)中查看它那么你一定在它的Readme.md中看到了Request和Response对数据部分的一些定义那就是JSON。虽然“战场”不能算是一个严格的RESTful接口的系统但是在数据交接的承载方式上它模仿了RESTful的样子。
另外一个部分是操作方式在“战场”系统中我们用了HTTP协议的Get和Post其实HTTP协议有很多方法但是我们仅仅用了这两种而RESTful的规定使HTTP的很多方法都被利用到了比如说Get方法用来获取资源Post方法用来新建资源或者更新资源再比如说Put方法用来更新资源、Delete方法用来删除资源等等。
在明白RESTful风格的接口和普通的HTTP协议接口的区别后我们现在来想一想你自己的框架需要添加什么内容才能支持RESTful风格的接口呢**这里我总结了两个方法:借助外力和自己封装。**
### 借助外力
这里我们RESTful的第一个数据交换的承载方式是JSON我们的框架在之前的“战场”系统中就已经使用了它虽然全部的操作都是参数拼凑的过程但这已经满足了我们的需求。
这时如果你仍要拼凑很多复杂的数据就需要使用JSON字符串和代码对象实体的转换它有一个专业的叫法**序列化和反序列化**。这个词语听着就很难理解,所以现在,我用一个生活中的小例子来告诉你,这个晦涩难懂的概念到底是什么意思。
如果你在商场看中了一款衣柜,但它很大,为了方便运输,就必须要先把它拆掉,运到家后再重新组装。你和商家协商好了,由他们为你把这个衣柜拆成可重组的零件运到家里,然后由你自己把这些零件重新组装成一个衣柜。
那么在这里商家把衣柜拆成各个零件、然后打包的这个过程就是“序列化”在代码中就是将一些程序对象转换成JSON等格式的字符串的过程。接下来你用这些零件再重新组装成一个衣柜这个过程就是“反序列化”在代码中就是JSON等格式的字符串转换成程序的对象的过程。
为了能让你的框架可以快速完成序列化和反序列化我建议你在代码中引入一个外部支持的库就像Python有JSON库、Java有Fastjson库。这些公开的库其实都不需要做任何的修改就可以拿来使用所以无论你使用哪种技术栈这样的基础库都是存在的你只需要在网上找一下然后花几分钟看一下怎么使用就可以拿到自己的框架里使用了。
### 自己封装
现在我们已经可以借助开源库解决数据交换的事情了但是RESTful风格接口和普通HTTP接口相比还有一个明显的区别那就是RESTful规定了HTTP的每一个方法都做固定的事情可我们原来框架中的Common类却只支持Get和Post方法因此你需要在Common类中加入Delete和Put方法的支持。具体的操作你可以依据下面这个代码段来完成
```
def put(self,uri,params=None):
'''
封装你自己的put方法uri是访问路由params是put请求需要传递的参数如果没有参数这里为空
:param uri: 访问路由
:param params: 传递参数string类型默认为None
:return: 此次访问的response
'''
url = self.url_root+uri
if params is not None:
# 如果有参数那么通过put方式访问对应的url并将参数赋值给requests.put默认参数data
# 返回request的Response结果类型为requests的Response类型
res = requests.put(url, data=params)
else:
# 如果无参数,访问方式如下
# 返回request的Response结果类型为requests的Response类型
res = requests.put(url)
return res
def delete(self,uri,params=None):
'''
封装你自己的delete方法uri是访问路由params是delete请求需要传递的参数如果没有参数这里为空
:param uri: 访问路由
:param params: 传递参数string类型默认为None
:return: 此次访问的response
'''
url = self.url_root + uri
if params is not None:
# 如果有参数那么通过delete方式访问对应的url并将参数赋值给requests.delete默认参数data
# 返回request的Response结果类型为requests的Response类型
res = requests.delete(url, data=params)
else:
# 如果无参数,访问方式如下
# 返回request的Response结果类型为requests的Response类型
res = requests.delete(url)
return res
```
在上面的代码中你可以看到我们为了实现HTTP协议的Put和Delete方法自己封装了put()函数和delete()函数。其实要实现RESTful风格的接口测试你只要封装HTTP协议对应的Method方法就可以了这样你的框架就能完美的支持RESTful风格的接口了。完成了这个操作后我们的Common类就既可以完成HTTP协议接口的测试也可以完成RESTful接口的测试了。
## 总结
到这里我们已经结束了今天的课程了。我们今天主要完成了RESTful风格接口的测试对比之前的例子以及你自己的测试框架针对框架中RESTful里缺失的部分我为你提供了对应的解决方法。
在文中我讲了很多内容但是完成RESTful风格接口测试主要是通过两步操作来为你的测试框架添加对应接口的测试能力的
1. 借助外力。目前网上已经有很多成熟的、各式各样的支持库,你要尽量拿来为己所用,而不要从零建设,这样,既弥补了我们开发能力不强的短板,也能提高我们的研发效率。
2. 自己封装。你要注意的是,自己封装和借助外力并不互相冲突,你要借助外力,然后将它封装到你自己的框架中,这是一个借力打力的好方法。
随着我们的课程的不断深入以及内容的不断丰富,我相信,你最终会获得一个完全适合你自己,又可以解决实际工作任务的测试框架,这也是你自己的接口测试武器仓库,里面有解决各种接口测试问题的方法。它会是一个私有仓库,里面每一个武器都是为你自己量身定制的,因此,每一件武器你用起来都会更得心应手。
## 思考题
我今天讲了RESTful接口测试并为你的私有测试框架添加了各式各样的新武器那么你能用你现在的新武器解决一个你负责的RESTful的接口测试吗在今天的框架中随着你实际工作的使用你又有了什么样的新设计呢
我是陈磊,欢迎你在留言区留言分享你的观点,如果这篇文章让你有新的启发,也欢迎你把文章分享给你的朋友,我们一起探讨和学习。