接口测试基础--扩展
上一节我们介绍了接口的请求示例、接口url组成、接口请求消息结构等内容,并用门禁卡的实例演示了两个接口测试的正常场景测试用例,接下来我们继续探讨p参数不存在、p参数值与接口定义不一致、p参数值为数字及中文等情况时的测试用例
1.异常场景测试用例
case1:参数p不存在
postman工具中,删除"?"后面的参数及参数值信息,即请求url为“http://127.0.0.1:5000/door?”,发送请求,返回结果如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <title>500 Internal Server Error</title> <h1>Internal Server Error</h1> <p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>
case2:参数p=push
postman工具中,将参数"p"的参数值修改为"push",即请求url为“http://127.0.0.1:5000/door?p=push”,发送请求,返回结果如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <title>500 Internal Server Error</title> <h1>Internal Server Error</h1> <p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>
可以看到,上述2个case执行结果都有报错,说明接口未对这些异常输入做容错处理,GB/T16260-2006《软件质量模型与度量》标准中,容错性是质量特性--可靠性的其中一个子特性,程序未做容错处理也就意味着不满足质量要求,可以按bug处理。
Tips:
GB/T16260-2006《软件质量模型与度量》质量特性:
质量特性 子特性 功能性 适合性、准确性、互操作性、安全保密性 可靠性 成熟性、容错性、易恢复性 易用性 易理解性、易学性、易操作性、吸引性 效率 时间特性、资源利用性 维护性 易分析性、易改变性、稳定性、易测试性 可移植性 适应性、易安装性、共存性、易替换性
事实上,我们Python代码确实未对异常情况做任何处理,大家也可以从代码实现的角度思考,如何修改代码才能修复上述缺陷,欢迎你在留言区留言和我交流,我会在课程解释前给出解决上述容错性bug的示例代码,供你参考练习,并在实际工作中如发现此类问题,可以为开发提供解决方案的建议。
报错的信息中,标签内数字为服务器状态码,常见的HTTP状态码如下(具体可参考 https://www.runoob.com/http/http-status-codes.html ):
- 200 OK:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
- 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
- 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
- 204 NO CONTENT - [DELETE]:用户删除数据成功。
- 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
- 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
- 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
- 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
- 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
- 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
- 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
- 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
case3:发送请求"http://127.0.0.1:5000/check_type?p=1"
接下来,我们一起分析,URL"http://127.0.0.1:5000/door?p=open"中,参数p的参数值如果替换为1,那么这个1到底是字符型还是数值型呢?不同数据类型程序就需要做不同的处理,因此我们有必要搞清楚URL中传递参数的参数值类型。
我们增加一个接口一起来验证,示例代码如下(示例代码参见GitHub:https://github.com/8784285/nowcoder.git ,文件路径:2.2/2.2-1.py):
#coding:utf-8 __author__ = 'Mr. null' from flask import Flask, request, jsonify app = Flask(__name__) # 定义check_type接口,返回p参数值及类型 @app.route('/check_type',methods= ["GET"]) def check_type(): p = request.args.get("p") return jsonify(code=0, msg="请求成功", p=p, type_p=str(type(p))) if __name__ == '__main__': app.run()
发送请求"http://127.0.0.1:5000/check_type?p=1"
返回结果:
{ "code": 0, "msg": "请求成功", "p": "1", "type_p": "<class 'str'>" }
从返回结果"type_p"的值可以看到,参数值1实际上是str类型。
如果接口要求参数值必须是数值类型,那么除了需要在接口文档中规定数据类型外,还需要在接口程序中对请求中的参数值做格式的转换,比如,如果约定开门、关门分别用数字0、1代替,那么代码实现如下(示例代码参见GitHub:https://github.com/8784285/nowcoder.git ,文件路径:2.2/2.2-2.py):
#coding:utf-8 __author__ = 'Mr. null' from flask import Flask, request, jsonify app = Flask(__name__) # 定义接口door1,对参数p的参数值做int转换 @app.route('/door1',methods= ["GET"]) def door1(): p = request.args.get("p") if int(p) == 0: return jsonify(code=0,msg="开门") elif int(p) == 1: return jsonify(code=1,msg="关门") else: return jsonify(code=10,msg='非法输入') if __name__ == '__main__': app.run()
我们分别用下述case测试door1
case4:发送请求"http://127.0.0.1:5000/door1?p=1"
door1返回结果:
{ "code": 1, "msg": "关门" }
case5:发送请求"http://127.0.0.1:5000/door1?p=8"
door1返回结果:
{ "code": 10, "msg": "非法输入" }
case6:发送请求"http://127.0.0.1:5000/door1?p=8.5"
door1返回结果:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <title>500 Internal Server Error</title> <h1>Internal Server Error</h1> <p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>
通过上面的3个case可以看到,当输入1和8这样的整数时,接口正常返回,但当输入8.5这样的小数时,接口返回报500错误,说明接口程序无法兼容小数类型的输入。
这里面涉及到开发语言的数据类型及类型转换的相关知识,另外,接口定义时通常要规定各个参数值的长度范围,即使没有明确限定,各数据类型因操作系统、数据库存储限制等因素,也是有输入上限的,因此,在设计case时,需要运用边界值分析法,设计参数值最小值、最大值的测试用例。
上面是p参数值为数字(实际url中为字符串)的情况,那如果p参数值为中文或者特殊字符,那接口请求的URL又会如何处理呢?
case7:发送请求"http://127.0.0.1:5000/door1?p=中文"
GET /door1?p=%E4%B8%AD%E6%96%87 HTTP/1.1
可以看到"中文"变成了"%E4%B8%AD%E6%96%87",这就是URL编码,RFC3986文档规定,Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符,保留字符包括:! * ' ( ) ; : @ & = + $ , / ? # [ ]
URL编码使用%百分号加上两位的字符——0123456789ABCDEF——代表一个字节的十六进制形式。
- 对于ASCII字符,符号"\"的16进制是0x5c,那么URL编码之后得到的就是"%5c";
- 对于中文字符,RFC文档建议使用utf-8对其进行编码得到相应的字节,然后对每个字节执行百分号编码。如"中文"使用UTF-8字符集得到的字节为0xE4 0xB8 0xAD 0xE6 0x96 0x87,经过Url编码之后得到"%E4%B8%AD%E6%96%87"。
通过上述case,我们看到参数值为8.5和参数值为中文的情况下,都会影响到接口程序的逻辑处理以及网络传输过程中的URL编码,所以在测试过程中设计包含整型、浮点型、中文、特殊字符类型参数值的测试用例是非常必要的。
2. 接口测试点大纲
上一篇和本节前面部分,我们介绍了一些比较典型的接口测试case,相信通过这些测试案例,大家也一定清楚了,接口测试不光要验证接口是否能按预期正常返回,更重要的是还需要验证接口在各种异常输入等场景下的容错性,另外,在实际业务场景下,还需要考虑接口安全性、性能、向前兼容等一系列问题,下图是接口测试的一些测试要点,可供测试用例设计时参考,接口安全、性能部分我们会在后续的专题中进一步介绍。
通过上面的测试点大纲,可以预见,一个接口如果包含多个参数,不同参数组合,可能就会有几十条甚至上百条用例,是否每个接口都有必要设计如此之多的测试用例?用例的设计又该遵循什么样的设计原则呢?
我的建议是:首先对接口按业务的重要程度做等级划分(如1/2/3级,重要级依次降低),已上线的接口可以参考线上接口访问量并数据结合业务属性确定重要级,没有上线的接口可以跟产品经理、开发同学沟通确定重要级。其次对接口用例也分重要级,具体可参考如下用例等级划分准则。
- 接口功能正常逻辑验证的典型值用例,等级:1(用于冒烟测试)
- 除正常典型值用例之外的正用例及异常用例,等级:2
- 可用性测试、入参默认值等用例,等级:3
这样在设计测试用例和执行测试用例的时候,重点工作就可以放在重要接口的重要用例设计上面了,执行的时候也按用例等级情况进行执行,层次就很分明了,用例的管理及维护也变得轻松起来。
<p> 本专刊共五章 21 篇正文及 5 个对应的 GitHub 项目,主要介绍了接口测试基础知识及测试用例设计方法,认证鉴权、加密验签,自动化测试,安全性测试,性能测试等内容,每一章节都有代码实例来剖析其原理,并提供了一个完整电商系统的代码,可以直接实操演练,让你知其然知其所以然,轻松搞定接口测试。加入专刊,你就加入了一大群志同道合的优质测试人圈子,同时还有和作者及作者的朋友们互动交流的机会。 本专刊购买后即可解锁所有章节,故不可以退换哦~ </p> <p> <br /> </p>