1. 接口测试
1.1. 什么是接口
API接口是Application Programming Interface的简称,是一些预先定义的函数,包括接口地址、传入参数和返回参数。
可以简单理解为,当需要访问某些数据,正常状态下传入合格参数,会收到该数据范围内的返回参数。
场景:在美团旅游频道,用户选定时间、地点后搜索航班,后台会调用搜索接口传入时间、地点等参数,接收航班类别、价格等参数,在前台页面上进行排列展示。同理,下单时会调用生单接口确认是否成单,支付时会调用支付接口完成交易,自动修改订单状态。
1.2. 什么是接口测试
接口测试主要用于外部系统与系统之间以及内部各个子系统之间的交互点,定义特定的交互点,然后通过这些交互点来,通过一些特殊的规则也就是协议,来进行数据之间的交互。
一般我们用的多的是HTTP协议的接口、WebService协议的接口,还有RPC(Remote Procedure Call Protocol)——远程过程调用协议的接口
不管是哪种接口,其本质就是发送一个request,然后服务器响应后返回一个response,然后我们对response进行分析,这即是接口测试。
接口的分类:
1.webservice接口 2.http api接口
webService接口是走soap协议通过http传输,请求报文和返回报文都是xml格式的,我们在测试的时候都用通过工具才能进行调用,测试。
http api接口是走http协议,通过路径来区分调用的方法,请求报文都是key-value形式的,返回报文一般都是json串,有get和post等方法,这也是最常用的两种请求方式。
一个URL就是一个接口:接口大致会分为一下几个部分:
请求协议:
http --- 普通的http请求
https --- 加密的http请求,传输数据更加安全
请求IP:就是指提供接口的系统所部署的服务器地址
请求端口:如果不填端口,默认是80,否则需要填写端口号
接口路径:指系统提供的接口在什么位置
接口参数:参数在接口路径后,用“?”来表示路径地址完了,剩下的都是参数了,用“&”来区分参数个数,
1.3. 为什么要做接口测试
随着系统越来越多,以及复杂性越来越高,为了保证系统的独立性,也为了使业务更加的独立,系统间的交互,越来越多的使用接口,这时候,为了保证数据的传输的准确性,接口测试也应运而生了,数据的错误,有可能引起系统的重大BUG,
大家都知道,接口其实就是前端页面或APP等调用与后端做交互用的,所以好多人都会问,我功能测试都测好了,为什么还要测接口呢?OK,在回答这个问题之前,先举个栗子:
比如测试用户注册功能,规定用户名为6~18个字符,包含字母(区分大小写)、数字、下划线。首先功能测试时肯定会对用户名规则进行测试时,比如输入20个字符、输入特殊字符等,但这些可能只是在前端做了校验,后端可能没做校验,如果有人通过抓包绕过前端校验直接发送到后端怎么办呢?试想一下,如果用户名和密码未在后端做校验,而有人又绕过前端校验的话,那用户名和密码不就可以随便输了吗?如果是登录可能会通过SQL注入等手段来随意登录,甚至可以获取管理员权限,那这样不是很恐怖?
所以,接口测试的必要性就体现出来了:
①、可以发现很多在页面上操作发现不了的bug
②、检查系统的异常处理能力
③、检查系统的安全性、稳定性
④、前端随便变,接口测好了,后端不用变
1.4. 接口测试的重要性
1.越底层发现bug,它的修复成本是越低的。
2.前端随便变,接口测好了,后端不用变,前后端是两拨人开发的。
3.检查系统的安全性、稳定性,前端传参不可信,比如京东购物,前端价格不可能传入-1元,但是通过接口可以传入-1元。
4.如今的系统复杂度不断上升,传统的测试方法成本急剧增加且测试效率大幅下降,接口测试可以提供这种情况下的解决方案。
5. 接口测试相对容易实现自动化持续集成,且相对UI自动化也比较稳定,可以减少人工回归测试人力成本与时间,缩短测试周期,支持后端快速发版需求。接口持续集成是为什么能低成本高收益的根源。
6. 现在很多系统前后端架构是分离的,从安全层面来说:
(1)、只依赖前端进行限制已经完全不能满足系统的安全要求(绕过前面实在太容易), 需要后端同样进行控制,在这种情况下就需要从接口层面进行验证。
(2)、前后端传输、日志打印等信息是否加密传输也是需要验证的,特别是涉及到用户的隐私信息,如身份证,银行卡等。
1.5. 接口测试工作流程
准备阶段(80%)
拿到开发的接口文档,并理解每个接口的参数及含义
了解被测试系统的业务流程
编写接口测试用例
执行阶段(10%)
测试用例/测试场景执行
测试数据/系统数据收集
分析阶段(10%)
数据汇总/日志分析
测试报告
1.6. 接口测试用例编写
接口测试用例编写要点
测试每个参数类型不合法的情况
测试每个参数取值范围不合法的情况
测试参数为空的情况
测试参数前后台定义的一致性
测试每个参数的上下限(这里容易出致命的BUG,如果程序处理不当,可能导致崩溃)
测试每个参数取值不合理的情况(包括取的值不属于自己,取值在这阶段不会出现,取值超出了自己所拥有的数量或者范围)
如果两个请求有严格的先后顺序,需要测试调转顺序的情况
自己和自己的交易、聊天等操作(这种特别容易遗漏)
1)、通用接口用例设计
①、通过性验证:首先肯定要保证这个接口功能是好使的,也就是正常的通过性测试,按照接口文档上的参数,正常传入,是否可以返回正确的结果。
②、参数组合:现在有一个操作商品的接口,有个字段type,传1的时候代表修改商品,商品id、商品名称、价格有一个是必传的,type传2的时候是删除商品,商品id是必传的,这样就要测参数组合了,type传1的时候,只传商品名称能不能修改成功,id、名称、价格都传的时候能不能修改成功。
③、接口安全:
1、绕过验证,比如说购买了一个商品,它的价格是300元,那我在提交订单时候,我把这个商品的价格改成3元,后端有没有做验证,更狠点,我把钱改成-3,是不是我的余额还要增加?
2、绕过身份授权,比如说修改商品信息接口,那必须得是卖家才能修改,那我传一个普通用户,能不能修改成功,我传一个其他的卖家能不能修改成功
3、参数是否加密,比如说我登陆的接口,用户名和密码是不是加密,如果不加密的话,别人拦截到你的请求,就能获取到你的信息了,加密规则是否容易破解。
接口用例
测试编号 | 所属模块 | 测试标题 | 功能名称 | 请求方式 | 请求参数 | 请求路径 | 请求头 | 请求体 | 预期结果 |
rpm_gzt_001 | 工作台 | 验证查询子任务完成状况参数正确,是否正常响应 | 查询子任务完成状况 | GET | creatorId=2 | http://192.168.103.12:8322/workBench/countSubTaskToday | { "status": 200, "message": null, "data": { "completeAllNum": 17, "unCompleteAllNum": 15, "completeNum": 11, "unCompleteNum": 10 }, "rel": true } | ||
rpm_gzt_002 | 工作台 | 验证查询子任务完成状况参数不填 | 查询子任务完成状况 | GET | creatorId= | http://192.168.103.12:8322/workBench/countSubTaskToday | 提示参数必填 | ||
rpm_gzt_003 | 工作台 | 验证查询子任务完成状况参数填,但是数据错误 | 查询子任务完成状况 | GET | creatorId=我真帅 | http://192.168.103.12:8322/workBench/countSubTaskToday | 提示参数错误 | ||
rpm_gzt_004 | 工作台 | 验证查询子任务完成状况参数填,但是数据长度等于12 | 查询子任务完成状况 | GET | creatorId=123456789012 | http://192.168.103.12:8322/workBench/countSubTaskToday | 提示参数过长 | ||
rpm_gzt_005 | 工作台 | 验证查询子任务完成状况参数填,传递空格 | 查询子任务完成状况 | GET | creatorId=空格 | http://192.168.103.12:8322/workBench/countSubTaskToday | 提示参数错误 | ||
rpm_gzt_006 | 工作台 | 验证查询任务信息参数正确,是否正常响应 | 查询任务信息完成状况 | GET | creatorId=2 bizDate="2018-06-04" pageNum=1 pageSize=10 | http://192.168.103.12:8322/workBench/queryTaskInfoByBizDate | "status": 200, "message": null, "data": { "total": 222, "rows": [ { "taskId": 13552, "activitiName": "wangwu", "bizDate": "2018-06-04", "exceptionSubTaskNum": 19, "completeNum": 19, "taskNum": 22, "executeStatus": 2, "taskType": 0, "userName": null, "subTaskList": null | ||
rpm_gzt_007 | 工作台 | 验证查询任务信息参数不填,是否正常响应 | 查询任务信息完成状况 | GET | creatorId= bizDate= pageNum= pageSize= | http://192.168.103.12:8322/workBench/queryTaskInfoByBizDate | 提示参数必填 | ||
rpm_gzt_008 | 工作台 | 验证查询任务信息完成状况参数填,但是Id数据长度等于12 | 查询任务信息完成状况 | GET | creatorId=212121212121 bizDate="2018-06-04" pageNum=1 pageSize=10 | http://192.168.103.12:8322/workBench/queryTaskInfoByBizDate | 提示参数过长 | ||
rpm_gzt_009 | 工作台 | 验证查询任务信息参数填,但是bizDate数据不是日期 | 查询任务信息完成状况 | GET | creatorId=2 bizDate=asd pageNum=1 pageSize=10 | http://192.168.103.12:8322/workBench/queryTaskInfoByBizDate | 提示参数错误 | ||
rpm_gzt_010 | 工作台 | 验证查询任务信息参数,传递空格 | 查询任务信息完成状况 | GET | creatorId= bizDate= pageNum= pageSize= | http://192.168.103.12:8322/workBench/queryTaskInfoByBizDate | 提示参数错误 | ||
rpm_gzt_011 | 工作台 | 验证查询单条任务信息参数正常,是否正常响应 | 查询单条任务信息 | GET | taskId=13554 | http://192.168.103.12:8322/task/querySingle | { "status": 200, "message": null, "data": { "taskId": 13554, "activitiName": "流程1", "bizDate": "2018-06-04", "completeNum": 22, "taskNum": 22, "exceptionSubTaskNum": 22, "executeStatus": 2, "taskType": 0, "userName": "zhangdan", "subTaskList": [ { "subTaskId": 153831, "activitiName": "流程1", "activitiTaskDesc": "持仓核对", "processId": "947", "executeStatus": 3, "executeTime": 0 }, { "subTaskId": 153830, "activitiName": "流程1", "activitiTaskDesc": "持仓核对", "processId": "946", "executeStatus": 3, "executeTime": 0 } ] }, "rel": true } | ||
rpm_gzt_012 | 工作台 | 验证查询单条任务信息参数不填 | 查询单条任务信息 | GET | taskId= | http://192.168.103.12:8323/task/querySingle | 提示参数必填 | ||
rpm_gzt_013 | 工作台 | 验证查询单条任务信息参数填,但不是数字 | 查询单条任务信息 | GET | taskId=帅 | http://192.168.103.12:8324/task/querySingle | 提示参数错误 | ||
rpm_gzt_014 | 工作台 | 验证查询单条任务信息参数填,但大于等于12位 | 查询单条任务信息 | GET | taskId=123123123123121 | http://192.168.103.12:8325/task/querySingle | 提示参数过长 | ||
rpm_gzt_015 | 工作台 | 验证查询单条任务信息参数填空格 | 查询单条任务信息 | GET | taskId= | http://192.168.103.12:8326/task/querySingle | 提示参数错误 | ||
rpm_gzt_016 | 工作台 | 验证推送手动任务中子任务数量信息是否正常 | 推送手动任务中子任务数量 | post | http://192.168.103.12:8327/task/manualTaskMessage | { "taskId": 13553, "activitiName": null, "bizDate": 2018-06-22, "completeNum": 10, "exceptionSubTaskNum": 2, "taskNum": 10, "executeStatus": 2, "taskType": 1, "subTaskMgmentVO": null } | |||
rpm_gzt_017 | 工作台 | 推送手动任务中子任务数量 | post | http://192.168.103.12:8328/task/manualTaskMessage | |||||
rpm_gzt_018 | 工作台 | 推送手动任务中子任务数量 | post | http://192.168.103.12:8329/task/manualTaskMessage | |||||
rpm_gzt_019 | 工作台 | 推送手动任务中子任务数量 | post | http://192.168.103.12:8330/task/manualTaskMessage | |||||
rpm_gzt_020 | 工作台 | 推送手动任务中子任务数量 | post | http://192.168.103.12:8331/task/manualTaskMessage |