TA的每日心情 | 擦汗 10 小时前 |
---|
签到天数: 1048 天 连续签到: 1 天 [LV.10]测试总司令
|
处理并校验结果:
对测试结果校验是这个框架中最难的部分,花最多时间进行试验、开发的。主要原因是系统的web service设计不太标准,不遵守REST service的设计原则。HTTP response虽说主要是json格式,但是还是挺多东西需要处理的。比如,有些里面有多余的斜杠,大括号等,需要先去掉,有些HTML嵌在json里面,有些json嵌在文本里面等等五花八门,这些都给我们的测试带来极大的挑战。(不得不顺便吐槽一下,不考虑测试的开发不是好开发,不考虑测试的框架不是好框架比如extJs 。。。呃。。。果然舒服一点了)。
除了上述一些麻烦需要预处理外,对结果的校验需要实现以下几个基本功能(其中使用了最流行的断言库chai,可以在npm下载):
完全一致对比:每次调用返回的结果跟之前录制的结果完全一致,这个其实是最为简单的,使用chai的“深等于”方法进行比较,字符串和JSON对象都可以。
黑名单:排除其中的一部分字符串,或者json字段,其他的进行“深等于”对比。
白名单:只选择其中一部分字符串,或者json字段,进行“深等于”对比。
如果返回的结果是json格式,进行黑、白名单校验,需要先把黑、白名单里面的字段查找出来,这里需要用到对象深度查找(类似深拷贝)技术,示例代码:
- function search(obj, key) {
- var arr = [];
- for (var i in obj) {
- if (!obj.hasOwnProperty(i)) continue; //exclude properties from __proto__
- if (i === key) {
- var o = new Object;
- o[i] = obj[i];
- arr.push(o);
- }
- if (typeof obj[i] === 'object') {
- arr = arr.concat(search(obj[i], key));
- }
- }
- return arr;
- }
复制代码 一个HTTP如果需要进行黑名单或白名单校验,黑白名单列表需在配置文件里设置好,否则默认进行完全一致对比。黑名单、白名单配置文件示例:
- "assertion_criteria": {
- "baidu.com/home/display": {
- "whitelist": ["<title>Home</title>", "name", "货币"]
- },
- "baidu.com/search": {
- "blacklist": ["pageInfo", "id", "时间戳"]
- }
- }
复制代码 以上具体使用那种校验,在大批量web service的回归测试中,未必能够,或者说未必需要提前设计好,最快捷的方法是通过几次试跑而试验出来:
第一次试跑由于没有设定任何黑白名单,所以按默认进行完全一致对比,测试通过的HTTP说明基本上可以按照完全一致进行对比测试(我的项目实践中90%都可以直接用这种方式,所以非常省事)。
对于失败的HTTP,则必须一个一个研究,看看导致失败的变化内容,把它们放入黑名单。如果只关心其中一部分内容的正确性,可以使用白名单方式。
多试几轮,直到所有的测试通过。在之后的时间里如果定期运行测试,还可能会发现有些会变化的内容,继续添加黑白名单,跑几天之后黑白名单就可以稳定下来。
还有一个必须提的关键点。json数据里面经常会有数组,数组就牵涉到排序问题。实践过程中发现有些HTTP每次返回的json数据是没有问题的,但是它的数组的元素是对象,而且顺序是随机的,这样就导致测试失败。但是没有很好的方法对这种数组进行排序,最后想到的解决方法就是把整个嵌套的json树扁平化,即把所有的末端数据全部取出来,放到一个数组里面再进行排序,这样可以保证数据完整,并且顺序固定。示例代码:
- function flatten(obj) {
- var arr = [];
- if(obj instanceof Array) {
- obj.forEach(function(element) {
- if(typeof element!=='object') {
- arr.push('ROOT:' + element);
- } else {
- arr = arr.concat(flatten(element));
- }
- });
- } else {
- for(var key in obj) {
- if(!obj.hasOwnProperty(key)) continue;
- if(typeof obj[key]!=='object') {
- arr.push(key + ':' + obj[key]);
- } else {
- if(obj[key] instanceof Array) {
- obj[key].forEach(function(element) {
- if(typeof element==='object') {
- arr = arr.concat(flatten(element));
- } else {
- arr.push(key + ':' + element);
- }
- });
- } else {
- arr = arr.concat(flatten(obj[key]));
- }
- }
- }
- }
- arr.sort();
- return arr;
- }
复制代码 把http reponse经过上述黑白名单、扁平化处理后,就可以使用chai库进行字符串或者json对象比较(chai的eql或者contain方法),判断结果是否一致。这里就不贴代码了。
测试报告:
对于测试结果的报告,主要有三件事要做。
控制台的显示:没有什么特别的东西,就是把所有的http的测试结果打印出来,通过的打勾,失败的打叉,加上相应的颜色,漂亮一点(模仿Mocha,呵呵),注意对于并行测试的顺序不能保证,所以显示顺序是乱的,但串行就是按照你录制的顺序显示的。
邮件报告:在测试的过程中把每个HTTP的测试结果记录下来,最后一次性发送邮件给相关人等。如果其中有失败的HTTP,则在邮件标题上显示失败。
log文件:主要是把测试失败的http的response记录下来,放到文件里面,方便查错。建议把log文件加上时间戳命名,然后把链接放在邮件里,不建议把log文件添加邮件附件,以防止邮件过大。
定期执行:
很多人直接把使用测试工具测试叫做自动化测试,其实不是很准确,如果次次要手动去启动,还要盯着它跑完以防出错,这种顶多算是半自动。真正的自动化测试必须是自己定期执行的,并且不需要太多的人工干预,只有测试失败的时候才需要去调查。
我因为没有太高的要求,所以把上面的过程基本上简单的设定为半小时跑一次。根据需要你也可以实现一些定点比如每天8点,13点,20点运行的job,以避开系统版本部署的时间,造成误报警。
总结
API测试最大的好处就是大
大减少了GUI自动化测试中的开发、维护成本,执行稳定且速度极快。它的另一个好处就是数据敏感性,非常适合测试返回数据集大而复杂的场景,数据集中任何字段返回非期望结果都会马上发现,肉眼测试是不可能做到的,如果在GUI自动化中来实现,也需要花费很大精力把数据从复杂的HTML里抠出来。
当然,每种技术都有它的强项和弱项。基于HTTP录制回放的自动化测试,最大的限制就是不容易把测试数据分离出来(当然对于一些简单的http请求,是可以分离的;对于非常复杂的请求一般很难做到),这就导致不同的测试数据需要重新录制。不过由于录制过程实际上非常简单快捷,对于回归测试来讲,这并不是一个很大的问题。
目前我所实践的API测试方法,主要集中在CRUD场景的测试中,暂不支持非实时返回结果的流程类场景,以后会增加相关支持。本文主要是分享HTTP层面的测试方法而非测试框架功能代码分享,希望大家从概念和测试方法上有所收获,具体的实现技术和代码,可以自行选择自己熟悉的语言。
总体上,对于表现层Web Service进行的测试既不是典型的端对端测试,也非集成或单元测试,在ThoughtWorks推崇的自动化测试金字塔理论中,它处于这个位置:
最后,照例强调一下,自动化测试不应该在回归测试的时候才做。
|
|