【精品投稿】自动化xml对比的一大利器!

 

头疼XML接口的自动化回归测试?试试这个吧!...





问题背景:

有一个复杂模块进行了架构重构,原有承担逻辑非常的复杂。在有限的时间内,除了手工测试重要功能以外,希望通过自动化执行对照测试,扩大覆盖面到尽可能多的情况。 预期两个模块对相同请求,返回的结果除了个别固定字段以外完全一致。需要排除个别字段的原因是这些标记不影响结果的差异,例如标示这个模块所在ip,请求发来的时间戳等。 模块接收http请求,返回的数据是xml。 这种请求在我们的接口测试当中很常见,于是想到做个工具来一块解决这类需要,提供自动化测试支持,后续可纳入到其他测试工具平台上。‍

问题拆解:



由于待测模块是标准的client-server模块中的server服务,我们最优先考虑的就是对两组测试模块输入相同的内容,直接检查测试组和对照组返回结果的差异,于是这个目标就被拆成了两部分:

发送请求:按照参数词表批量发送http请求给测试模块并收回结果,保存备查。 做出对比:将拿到的两份xml文档进行对比,并输出对比结果。‍



功能分析:



其中发送请求一方面大家想必不会陌生(我们这里用了python的requests库,requests.post()一句话就能拿回目标模块结果),重点就落在第二项做出对比上。已知两份xml结构的文档,它们需要从哪些维度衡量差异呢?

我们举个简单的例子:









blahblah1...


blahblah2...






画出图来是这样的:



经过思考,基于xml本质上的树状结构,比较xml文档实质上就是对树的比较。加上之前我们对json文档差异做过类似的思考,对xml文档差异提出了这几点差异考察点:

(1) 节点本身内容的差异。例如两个文档里pagetitle节点的内容。

(2) 节点自身属性的差异。例如info里的date属性,实际应用中不仅是节点本身里面的内容会被用到,这取决于上层使用数据的模块内部逻辑。

考虑到属性差异和属性结构的差异,最终将其分成了两个差异进行分别统计:属性差异和属性结构差异。



如图,html中的meta节点有name和content两个属性,如果是缺失了name字段,那么提供数据的模块很可能有问题,而content里的内容就很可能是取决于数据的。

(3) 子节点的差异。细分包括子节点结构上的差异,子节点属性差异的集合,子节点内容差异的集合。对子节点差异的集合,需要一个计算方式来决定它最后如何影响本节点。



如图,举例使用最简单的平均计算方法,得到根节点相似度为83.3%,越下层的节点差异反馈上来影响越小,但实际上results节点的重量更大。‍

子节点结构的差异又分成两个状况:

(1) 是某个名称的子节点,在一份xml中存在,另外一份xml中不存在。例如测试xml里没有info节点,这种情况下我们认为严重程度是比info节点内容不同要高,应该单独给不同的警报。

对上层模块来说,取重要字段解析错误的风险会加大,比危险一些。



(2) 是相同TAG名称子节点组的数量和顺序不同,例如一个results下包含2个或是3个节点的差异,或者即使数量相同,其顺序位置颠倒也认为是差异项。作为足够健壮的测试工具,应该有开关/配置功能支持是否进行这样的检查。 *在我们的现有测试方案中,认为位置不同是存在差异的。例如搜索出来的同一条结果,排在第1和第2是完全不同的。‍



如图,用逐个位置比较的方式,我们看到只有3号位置完全一致,相似度为0.25,如果顺序不相关,相似度是0.75,相差300%。

对于上述需要忽略一些节点的需求,则需要设立黑/白名单的机制。经过实战效果反馈,我们设立了两种机制:

(1) 内容-属性关键/忽略机制。关键节点/关键节点属性标示如果这个节点的内容/属性不符则认为整个节点完全不相同,不再检查下面的节点。除了忽略掉固定有差异的节点外,关键节点的设计能提高报警的有效覆盖程度。

实践中存在results下两个对应位置result节点是完全不同的东西,强行对比会产生海量diff报警,然而实际上只需要一条节点Id的检查即可起到足够的作用。



如图,不同的result下面可能会有不同的结果,如果不同的网站对比,巨大的结构差异会引起大量报警。但我们看到url不同就知道这两个节点完全不同了。

(2) 数量-结构忽略机制。这个是针对像 results 这样拥有一组相同名称的节点,衡量其子节点相似程度设计的。例如下图中是否允许result节点的数量差异。





那么问题来了,判断逻辑本身好写,一般直接return 完全相似的1或者完全不相似的0即可,但如何在xml中定位元素的路径?

我们采取的方案是沿用XPath的写法,单独写一个类来对当前路径(如/root/resutls/result[1])是否在指定的黑/白名单list中进行判断。 每种类型的黑/白名单(例如,关键节点,关键节点属性,忽略节点,忽略节点属性,等等…)设置一个list,从文件中读取。‍

计算方法:



从实际测试业务的效果来看,反馈节点差异详情更重要,统计数字在测试环境中更少关注。

相似度多少才算是正确的?实际如何给出最终的相似度数据这点是和业务相关的,没有一概而论的方法。

由于关于相似度的计算逻辑上,和实际业务相关,我们这里只提供一些需要考虑的思考点供大家参考。

(1) 底层节点的差异反馈向上一层节点,跟这个节点自己的差异比起来,占的比例有多少?

(2) 同层次之间节点的差异总和如何计算,才能反馈给上一层?

(3) 属性的差异和内容的差异是否合并?如果合并,各自应该占比多少?

(4) 命中关键/忽略名单的节点,是否直接返回100%不相似或者相似,不进行其他类型的检查?

在实现上,我们使用python的xml.etree下ElementTree解析xml,通过递归的方式遍历xml文档的全部节点,递归的同时通过参数传递当前路径,用于黑/白名单比对和检测到差异点时输出路径。‍

输出报告:

综上所述,最终的输出报告由以下几部分组成:

(1) 统计数据。叶子节点的各项差异会反馈到父节点,逐层最终返回到根节点。对于最终的差异分,以1表示完全相似,0表示完全不相似。

(2) 对上述数据的按出现频次的统计,用来反映哪些节点/属性最频繁出现差异。频繁出现的差异往往也是最需要关注的。

(3) 详细差异报告,每个进行差异判断的逻辑里一旦发现差异,都应该向详情报告里写明节点路径,两个节点各自的对比差异项。

(4) 抓取的xml实际文件和标号。详细差异报告的项目应该能找到对应的真实xml数据,方便从全局查看和分析问题。

(5) 这次测试涉及的模块信息,如测试执行时间,base、test对应代码版本。

以上就是一种建立xml结构文档的比较方案,从这次项目中我们跑1000个查询对比的速度在10分钟以内,实际上速度瓶颈还在抓取而不是分析操作上,因为我们要尽量保证被抓取模块下游返回数据的稳定。

这个方案的建立有这几个优点:



(1) 它实现起来很快,我们用python从思考到实际执行,依照开发反馈修改,只用了一个人一周多的时间。

(2) 对xml文档100%全覆盖,能够迫使项目人员去思考一些不起眼的字段是否存在问题。

实践中有差异的字段,开发人员本身也不一定全知道它们的具体含义。

(3) 绕过了数学算法部分,降低设计工具的门槛,同时也支持后续引入算法甚至机器学习来对节点的权值进行更合理地计算。

(4) 它可以匹配任意结构的xml,和其他自动化测试人工维护一份XPath列表与预期值相比,这个方案更加灵活,适合大规模重构和效果对比,能够发现预期之外的问题

(5) 计算xml差异的计算量对服务器算力来说足够快,可以支撑。对线下回归测试来说,瓶颈一般是体现在数据获取上。

(6) 如果手工测试是基于上游模块最终返回结果进行检查的,直接比较测试模块的xml,粒度更细,能够发现不直接体现在上游模块结果中的差异。


    关注 搜狗测试


微信扫一扫关注公众号

0 个评论

要回复文章请先登录注册