本篇开始,将陆续介绍基于Java+HttpClient+TestNG的接口自动化测试框架。(这里需要阅读的童鞋们有Java的编码知识及HttpClient和TestNG的使用经验。)
首先,我们需要讨论一下,什么是接口测试?为什么要做接口测试?以及我们这个框架解决的问题是什么。
什么是接口测试?首先需要说明一下什么是接口。按照百度的定义,接口------外部系统与系统之间以及内部各个子系统之间的交互点。这么说有点抽象,简单来说,如果我要在一个网页中显示一些数据/文字什么的,我需要有数据来源,碰巧这些数据来源是需要经过逻辑计算的,又碰巧这些数据来源不是来自同一个服务器。那么,如果我直接把这些逻辑和请求都写在页面上显然是不合适的。这时,我们需要去请求一个接口,这个接口就是页面显示和后台服务之间的交互点。接口测试就是测试这个交互点的功能是否正常,我所需要的数据是否按既定的逻辑进行返回。从这个意义上来说,接口测试非常简单,我们只需要考虑各种输入条件下,会产生相应的什么结果,是最为简单的黑盒测试!
那么为什么要做接口测试呢?无他,总体来说就是成本低,效果好,速度快。
在前端的童鞋还没有完成UI页面之前,传统的测试是不太可能进行的。而接口测试不需要UI界面,直接通过接口去验证后台逻辑。而且,如果有人通过抓包,直接跳过前端的校验,去进入后端的程序。也是一件很危险的事情。因此,接口测试可以尽可能早的开展。越早介入测试,发现的问题解决起来的成本是越低的。在传统的测试中,开发没有将完整产品提交给测试时,测试这边是无法工作的。而在现在流行的敏捷开发中,开发可以写完一个接口就进行一轮接口测试的回归,以最小的代价快速保证质量。
接口测试性价比很高,很多公司也比较喜欢进行接口测试。那么当我们做接口测试时,到底需要做哪些方面的工作呢?
- 获取需求文档和接口文档 --------> 实际有可能没有,有可能不全。
- 通过对需求文档分析出接口的业务逻辑要求以及业务边界 -------->对测试的业务场景进行构建
- 通过对接口文档分析出接口的技术指标(接口地址、请求方式、入参、出参)-------->实际测试的之前必须搞清楚要访问接口的信息。
- 接口测试用例设计(着重于接口测试数据准备)-------->业务数据的准备尤为重要。
- 使用接口测试工具进行接口测试 --------> 可以使用Jmeter,Postman等软件,也可以使用自动化测试框架
- 接口缺陷管理与跟踪 -------->生成测试的log与报告
- 接口自动化持续集成 -------->用于Jenkins平台
在这里,有一个误区,很多人认为会使用接口测试工具就是会接口测试。其实接口测试远远不止是工具的使用,Jmeter也好,Postman也好,这些工具都是我们在进行接口测试过程中能够更方便的进行测试,而工具仅仅是工具,真正核心部分还是接口测试用例设计以及测试思维。
既然已经有了接口测试的软件,也能一定程序上实现接口测试的自动化操作。为什么我们还要费劲周折的去写接口自动化测试框架呢?说实话,我一开始也不是很明白。直到后来,我遇到了这样一个接口,
这个接口的访问需要输入一个sign作为参数。而这个sign的获取方式如下:
int A 为当前系统的Unix时间戳。(即1970年1月1日到现在有多少秒),String B为当前用户所对应的secret数据库id(一个32位字符串),String C为当前的appkey(可以通过另外一个接口获得),
将int A转为16进制,然后变成字符串,与B及C拼接成字符串D,然后对字符串D取MD5的值,作为sign。
说实话,这个我不知道用Jmeter或者Postman怎么做。尤其是int A每一秒都不一样。在这种情况下,自己写个工具来解决,是不是方便很多呢?
针对一些使用工具进行接口测试的痛点,就说说我们这个接口自动化测试框架能够解决哪些问题。
- 采用数据驱动方式来解决大量功能重复性接口的测试。
- 针对返回JSON字符串,采用JSONPath的模式来精准判定JSON的内容。
- 可以生成比较直观的报告。
当然,也可以集成很多小工具。比如上面提到的计算MD5的值。
先开个头,想想一个接口的请求及返回是由哪些构成的呢?
请求的有:url,访问方法,请求头,body,参数等,返回的有json字符串,状态等。
我们可以根据接口的访问和返回的内容,做成一个Bean,来记录请求和返回及判定的数据,而这些数据都记录在Excel中。
现在做成Excel的基础类:
package apiTest.bean; public class baseBean { private String excelName; private String sheetName;
public String getSheetName() { return sheetName; } public void setSheetName(String sheetName) { this.sheetName = sheetName; } public String getExcelName() { return excelName; } public void setExcelName(String excelName) { this.excelName = excelName; } }
然后,我们的api请求及返回继承这个基础类。
package apiTest.bean; public class apiDataBean extends baseBean { private boolean run; //是否运行 private String desc; // 接口描述 private String method;//访问方法 private String url; //接口访问url //header的情况相对复杂,可以设置公共header,也可以针对个别请求来设定访问的header。 private String header; private String body;//接口请求时的body private boolean contains; //是否对返回的json字符串中作包含判定(针对接口返回内容较多,不好具体制定路径的情况) private int status; //返回状态 private String verify;//判定内容 private String save; //需要保存的内容 private String param; //接口发送需要的参数 private int sleep; //暂停时间 public boolean isRun() { return run; } public void setRun(boolean run) { this.run = run; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getHeader() { return header; } public void setHeader(String header) { this.header = header; } public String getBody() { return body; } public void setBody(String body) { this.body = body; } public boolean isContains() { return contains; } public void setContains(boolean contains) { this.contains = contains; } public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public String getVerify() { return verify; } public void setVerify(String verify) { this.verify = verify; } public String getSave() { return save; } public void setSave(String save) { this.save = save; } public String getParam() { return param; } public void setParam(String param) { this.param = param; } public int getSleep() { return sleep; } public void setSleep(int sleep) { this.sleep = sleep; } @Override public String toString() { // TODO Auto-generated method stub return String.format("desc:%s,method:%s,url:%s,param:%s", this.desc, this.method, this.url, this.body); } }
好的,这样我们就对接口及返回数据制作了一个类,这个类就是接口测试的数据模型。
开篇先写道这里。之后我们来讨论配置的读取和设定。