问题背景:

在测试&部署监控过程中,我们常常会遇到外部接口返回数据不靠谱的时候。最常见的场合是从某个http获取如json和xml等结构化的结果,进行解析并处理,在这时候出现以下这几种常见类型的错误:

(1)整个结构不完整。直接无法解析json/xml。

(2)编码错误,常见的gbk/utf8错误

(3)超长数据/非法字符。

(4)数据类型不匹配。需要是数字的给了字符串,该是数组的给了字符串等,对json本身来说没问题,程序处理就会错误或者崩溃。
(5)字段缺失或者为空,这个情况对json本身来说也是没问题的,处理进程固定要去取这里的字段就会出问题,或者进程本身没问题,但实际展现出问题。

例如json描述一个商品最近30天的售价,提供一个数组里有30个数据来画点,json里这个数组为空,从数据格式上来说没问题,但实际画点时展现即为空。 
截图是来自一份合作方的数据,箭头指向的是上证指数曲线的点,如果点数据完全缺失(为空)则画曲线的界面会显示为空。在json结构上则仍然验证为合法。

解决问题的现状:

对上述问题,我们有一些简单的自动化监控手段,通过定期抓取http接口再获取其中内容这一步比较简单,接下来我们会验证http状态码(200正常,非200认为是有问题)和长度,如果过短(例如少于20字节)则认为是无效。 
还有一些自动化case会先人工看一下接口返回的具体内容,然后再作为case检查点,检查抓取接口中是否存在固定字符串片段,以此进一步验证返回结果的正确性。这里我们仍然进行的是字符串粒度上的检查。 
解决问题思考: 
如果只通过字符串的方式检测长度,这个粒度过于粗糙,难以发现上述详细一些问题。检查固定的字符串片段存在,能部分弥补上述不足,但仍然无法检查背景中提到的诸如字段缺失的问题。 
但是若要检查字符串完全相同,则要求接口每次返回的数据完全相同,和实际应用情况不符,维护case难度大。那么,我们的思路就转向如何对数据结构体进行检查。

总的思路出于以下几条:

1.根据历史接口请求结果作为范本,提取特征作为约束对新数据进行检查。提高工具本身的适用范围。
2.接口返回的数据应该可以化为结构体,通过对结构体字段的条件约束来判断数据检查是否通过。
3.对有些字段内容可以进行二次解析,保障其中数据的合法性。
4.基于历史数据特征进行统计,辅助对数据字段进行正确性检查,进一步降低维护条件约束的难度。

接下来我们逐步来设计我们以上思考功能。 
解决问题的设计:

0.用什么代码?

现在任何一种主流语言都有成熟的json/xml解析库,幸运的是作为正确性检查,这个规模我们基本不需要考虑性能问题。当速度不可接受的时候可以考虑多进程分开跑来环节压力。
推荐脚本语言python/php,开发起来更快一些。作为一个轻量的检查工具甚至只是个lib,它应该尽量简单,方便使用,方便纳入现有的测试框架之中。

1.如何抽取特征?

无论是json还是xml,本质上都是树形结构。基于我们最终目的是进行验证的考虑,把json/xml解析为树是个不错的主意。既然预期结构完全相同,那么我们可以依照key,依次遍历检查树的每个节点,比对被比较object是否一致。 
以json为例,我们输入两个json字符串,将其转化为object。如果是复杂结构,则再对object进行递归比较,如果是int或者string,则按既定规则比较。

function compare_json($in_json, $diff_json){
   $json = new Services_JSON();
   $start_object = $json->decode($json_str_from_file);
   $diff_object = $json->decode($json_str_diff_from_file);
   return compare_all($start_object, $diff_object);
}

compare_all(obj2) 进行遍历,先判断类型再进行比较,返回布尔值检查结果向上传递。 
如图,我们举个例子,查询某个小组成员的数据,根据json生成的树

{ 
  "name":"name1",
  "date":123,
  "members":[
     {
        "name":"alice",
        "level":5,
        "lastpost":{
           "title":"noname1",
           "date":500
        }
     },
     {
        "name":"bob",
        "level":0,
        "lastpost":{
           "title":"noname2",
           "date":501
        }
     }
  ]
}

对应的结构

2.约束条件都有哪些类型?

根据实际应用情况的不同,可以按需求调整。特别是数组由于数量一般不一致,可以考虑在非空的条件下只取第一个进行结构验证,也可以考虑遍历取每一个节点进行相同的结构验证。 
在这里举一些例子作为常见的检查参考:

(1)根据key进行遍历,如果对照的测试数据直接取不到key对应的object,则认为有问题。在取到数据的情况下进行比较:
(2)两边数据类型一致
(3)样板数据非空的情况下,检查数据应该非空
(4)样板数据为空,检查数据为非空或空都可以
(5)数组里的元素个数应该保持一致
(6)如果不是叶子节点,它下面还有某种结构的话,用相同规则处理下面的子树。

3.对其中个别节点的附加检查方式:

我们同样考虑,在一些case的执行中,要求对其中一些重要的节点做出复杂检查操作,这些检查操作是根据case来的,不能适用到其他case上。最重要的问题是如何定位节点。 
例如上述每条json数据中,希望检查每个level都在5以上… 通过path定位需要一个辅助工具来索引json返回对应的数据。 
对于xpath for json,php有第三方的lib提供了jsonpath来执行类似xpath的检索功能。通过实验检查可行,也可以单独根据xpath的语法写一个解析器,但这里不符合我们对快速实现最终检查目的这个目标。是否自己写lib来支持,取决于工期的长短。 
http://goessner.net/articles/JsonPath/ 
一个简单的实例,对每个level进行检查。

//load library
require_once ('lib/JSON.php');
require_once ('lib/jsonpath-0.8.1.php'); $json_newstr = '{"name": "name1", "date": 123, "members": [{"name":"alice", "level": 5, "lastpost": {"title": "noname1", "date": 500}} , {"name":"bob", "level": 0, "lastpost": {"title": "noname2", "date": 501}}]}'; echo "json str: $json_newstr\n";
$json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
$start_object = $json->decode($json_newstr);
$result = jsonPath($start_object, "$..members..level");
echo "got all levels...\n";
var_dump($result);
$check_result_ok = true;
foreach($result as $level_to_check){
   if($level_to_check <= 0){
       $check_result_ok = false;
   }
}
var_dump($check_result_ok);

运行上述片段对json字符串进行检查

task start...
json str: {"name": "name1", "date": 123, "members": [{"name":"alice", "level": 5, "lastpost": {"title": "noname1", "date": 500}} , {"name":"bob", "level": 0, "lastpost": {"title": "noname2", "date": 501}}]}
got all levels...
array(2) {
 [0]=>
 int(5)
 [1]=>
 int(0)
}
bool(false)
task end. run check for 0 time(s)

我们输出检查结果为false,发现了一条不符合预期的数据。

4. 如何基于历史特征进行统计?

在以上部分我们了解如何提取特征后,我们可以考虑将其按照结构化保存在mysql里。在前几步执行过程中我们已经遍历了json对应object的树状结构,以及通过xpath等树状描述对节点进行定位。将这几个步骤组合起来即可:以接口为key,按需要保存若干特征描述,对后续提取的结果进行检查。 
以上面的样例json为例,我们可以保存每次抓取检查时,/members[]数组下的元素个数,当和历史平均值波动大于80%时认为是有问题报警。

5. 基于字符串的检查…

除了上述的详细检查外,我们依然需要对字符串进行一些检查,例如编码、总长度和结构完整性。最后一点比较简单,考虑调用lib时parse失败,如果失败说明json/xml结构不完整,保存现场供人工查看,调整case。

以上就是关于数据接口检查类的自动化测试思路,在设计上我们考虑到现在一些自动化监控/测试实践中遇到的问题,和趋向最新机器学习思路提取特征的想法提出的想法。

carry-检查数据接口返回数据合法性的更多相关文章

  1. ASP.NET API(MVC) 对APP接口(Json格式)接收数据与返回数据的统一管理

    话不多说,直接进入主题. 需求:基于Http请求接收Json格式数据,返回Json格式的数据. 整理:对接收的数据与返回数据进行统一的封装整理,方便处理接收与返回数据,并对数据进行验证,通过C#的特性 ...

  2. 酷友观点/经验:支付接口返回数据接收地址,session数据丢失(或者说失效)的问题浅析(原创文章)

    酷友观点/经验:支付接口返回数据接收地址,session数据丢失(或者说失效)的问题浅析(原创文章)   最近手头在开发一个游戏官网,在支付模块采用神州付技术支持,神州付数据表单中要求提供服务器返回地 ...

  3. python接口自动化26-参数关联和JSESSIONID(上个接口返回数据作为下个接口请求参数)

    前言 参数关联是接口测试和性能测试最为重要的一个步骤,很多接口的请求参数是动态的,并且需要从上一个接口的返回值里面取出来,一般只能用一次就失效了. 最常见的案例就是网站的登录案例,很多网站的登录并不仅 ...

  4. python3乱码问题:接口返回数据中文乱码问题解决

    昨天测试接口出现有一个接口中文乱码问题,现象: 1 浏览器请求返回显示正常 2 用代码请求接口返回数据中文显示乱码 3 使用的python3,python3默认unicode编码,中文都是可以正常显示 ...

  5. mock模拟接口返回数据

    mock,是python中模拟接口返回数据 1.安装 pip install mock import unittest from mock import Mock def add(a,b): pass ...

  6. 通过Fiddler肆意修改接口返回数据进行测试

    [本文出自天外归云的博客园] 方法介绍与比对 在测试的过程中,有的需求是这样的,它需要你修改接口返回的数据,从而检查在客户端手机app内是否显示正确,这也算是一种接口容错测试,接口容错测试属于app性 ...

  7. php 请求另一个服务器接口返回数据

    <?php /** * Created by PhpStorm. * User: thinkpad * Date: 2015/7/17 0017 * Time: 13:24 */ class A ...

  8. vue项目中使用mockjs模拟接口返回数据

    Mock.js 是一个模拟数据生成器,利用它,可以拦截ajax请求,直接模拟返回数据,这样前后端只要约定好数据格式,前端就不需要依赖后端的接口,可以直接使用模拟的数据了. 网上介绍mock的教程也较多 ...

  9. POST请求成功,但接口返回数据不正确

    事件:使用Jmeter做APP的搜索接口测试,请求成功了,但无论keyword是什么“内容”(这里的内容是带引号的哦),接口返回的内容都是:未匹配到搜索结果 排查问题: keyword=“世界” st ...

随机推荐

  1. Kibana5 数据探索使用(Discover功能)

    认识Kibana Kibana 是一个为 Logstash 和 ElasticSearch 提供的日志分析的 Web 接口.可使用它对日志进行高效的搜索.可视化.分析等各种操作.Kibana的使用场景 ...

  2. 【SignalR学习系列】4. SignalR广播程序

    创建项目 创建一个空的 Web 项目,并在 Nuget 里面添加 SignalR,jQuery UI 包,添加以后项目里包含了 jQuery,jQuery.UI ,和 SignalR 的脚本. 服务端 ...

  3. 浅谈layer.open的弹出层中的富文本编辑器为何不起作用!

    很多童鞋都喜欢用贤心的layui框架.是的,我也喜欢用,方便,简单.但是呢,有时候项目中的需求会不一样,导致我们用的时候,显示效果可能会不一样,好吧.这样的话,个别遇到的问题总是解决不好,但是呢还是那 ...

  4. Pandas: 如何将一列中的文本拆分为多行? | Python

    Pandas: 如何将一列中的文本拆分为多行? 在数据处理过程中,经常会遇到以下类型的数据: 在同一列中,本该分别填入多行中的数据,被填在一行里了,然而在分析的时候,需要拆分成为多行. 在上图中,列名 ...

  5. 灵玖软件Nlpir Parser语义智能内容过滤

    Internet是全球信息共享的基础设施,是一种开放和面向 所有用户的技术.它一方面要保证信息方便.快捷的共享;另一方面要防止垃圾信息的传播.网络内容分析是一种管理信 息传播的重要手段.它是网络信息安 ...

  6. java_==和equal方法

    java测试两个变量是否相等有两种方式: 一种是利用"=="运算符 值和对象的判断 一种是利用equals()方法 只是值的判断 1.如果两个变量是基本类型变量,且都是数值类型(不 ...

  7. [补档][Tvyj 1729]文艺平衡树

    [Tvyj 1729]文艺平衡树 题目 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结 ...

  8. VMware的安装和使用

    注:内容系兄弟连Linux教程(百度传课:史上最牛的Linux视频教程)的学习笔记. VMware的安装和使用 1. 虚拟机的安装 这里安装虚拟机VMware10,下载安装程序,双击安装-->为 ...

  9. DDL中drop-alter table

    一.DROP TABLE语句:用于删除数据表 DROP TABLE removes one or more tables. You must have the DROP privilege for e ...

  10. 响应式布局 —— Demo

    响应式布局实例演示What is 响应式布局? 响应式布局是Ethan Marcotte在2010年5月份提出的一个概念,简而言之,就是一个网站能够兼容多个终端--而不是为每个终端做一个特定的版本.这 ...