1、已知json串构成的情况下判断

  先构造一下场景,假设已经把各个数据都移除掉不对比的字段

                          图1

  预期、实际结果,复杂接口返回多层嵌套json时,同下

                          图2

  预期、实际结果值为:{child_json1:list1,child_json2:list2}

  其中list1、list2为child_json,值为:[dict1,dict2]

  其中dict1、dict2为child_child_json,最底层json,无嵌套,值为:{key1:value1,key2:value2}

  如果一开始就直接判断预期结果与实际结果一致,当list1、list2不一致时,会怎样呢,我们把list2做下修改,如下图

                          图3

  直接对他们进行判断

                          图4

  结果如下图,异常提示把整串的list抛出来了,当字段数多的时候,就比较难定位问题

                          图5

  如果对child_json这层开始判断,也是类似的,因此我们要从小的单元开始判断,即从child_child_json(即无嵌套的dict)开始判断。

  1)先判断child_child_json是否一致:直接用Dictionaries Should Be Equal,就可以

    假设取到了child_child_json_预、child_child_json_实,则判断如下:

                          图6

  PS:从上一篇,我们可以看到RF自带的Dictionaries Should Be Equal、Lists Should Be Equal在判断无嵌套的dict、list时,错误提示很清晰。

  2)如果所有child_child_json相等,再判断child_json(值为list)是否相等:用Lists Should Be Equal判断。

    ①先分别获取两个child_json的长度,并判断是否相等

    ②for循环,根据下标分别获取child_child_json,1)中的方法判断所有child_child_json是否相等

    ③最后判断两个child_json是否相等(本例中当所有child_child_json相等时,不需要这个也行)

                          图7

  3)如果child_json都相等,最后再判断预期、实际结果(值为dict)是否相等:用Dictionaries Should Be Equal判断。

    ①先分别获取json的keys,并判断是否一致

    ②for循环,根据key分别获取child_json,2)中的方法判断所有child_json是否相等

    ③最后判断两个json是否相等

                          图8

  分别看一下两个值一致和不一致的执行情况,一致时如下:

                          图9

  值不一致时,如下图,child_json2中第一个dict的key2的value不一样:

                          图10

  执行结果如下,发现离错误最近的path打印,值定位了index为0,没有定位到是child_json2,还需要往前找。

                          图11

  我们在前面判断child_json是否相等的方法2)中,做下修改,加一个${path}的参数,用于传父path

                          图12

  在case这边,把${key}作为参数传入

                            图13

  执行结果如下图,比较清晰的说明了是child_json2/0下的值不一致

                            图14

2、其他构成格式的json串

  {"key1":"value1","child_json":[{"child_json_key1":"child_json_value1","child_child_json":[child_child_json_dict1,child_child_json_dict2]},child_json_dict2]}

  如上的格式,第一层的key,对应的value有普通字段,也有child_json,child_json为list,child_json下又有普通字段及嵌套的child_child_json,这种情况下,1中的代码就不适用了,因此要考虑下如何兼容各种格式的json串,总不能换一个格式的json串,就写一套判断方法。

  从1中的实现,可以看到,判断两个json串是否相等,我们的思路是:

    ①先初步判断:如果是dict,先判断他们的keys是否一致;如果是list,则先判断他们的长度是否一致

    ②如果json下有子json串(dict或list),找出子json串,对子json串进行判断

    ③重复①②,一直到最后一层json(底下没有dict或list)

    ④从最后一层的子json,一层一层往上进行判断,用Dictionaries Should Be Equal或Lists Should Be Equal判断是否相等。

    PS:过程中加参数path,用于定位路径

    写成脚本:

    ①类型是dict或list,走对应的初步判断

                            图15

    加一下方法:判断dict_json串keys是否一致、判断list_json串长度是否一致

                            图16:判断dict_json串keys是否一致  

                            图17:判断list_json串长度是否一致

    当然,在这之前,要先获取json串是dict还是list

                            图18

    ②获取child_json,因为child_json可能存在0~N个,因此把它存为list

                            图19

                            图20

    加一下方法:遍历dict_json,获取child_jsons、遍历list_json,获取child_jsons

                            图21:遍历dict_json,获取child_jsons-1

                            图22: 遍历dict_json,获取child_jsons-2

                            图23:遍历list_json,获取child_jsons-1

                            图24: 遍历list_json,获取child_jsons-2

    再新加下方法:类型为dict或list的,以child_json1/child_json2/path,三个为一组的格式,加进child_jsons_list(这里三个值也可以拼成list再加)

                            图25:类型为dict或list的,加进child_jsons_list

    ③通过for循环,一个一个对child_json进行判断

                            图26

  要重复①②的步骤,所以就有这么一个过程:初步判断->找子json->初步判断->找子json->初步判断->找子json……->找不到子json时进行后续的操作

  有点类似于故事:从前有座山,山里有座庙,庙里有个和尚,和尚在讲故事,从前有座山,山里有座庙,庙里有个和尚,和尚在讲故事,从前有座山...

  区别点在于故事是无限循环,没有结束的事件,而我们的过程有个结束的标志:找不到子json。因此我们这里可以用递归来实现。

  先拿故事,来说明下递归的实现,先看下循环实现,这里只设置30次

                            图27

  结果如下

              图28

  递归实现:先封装个方法:山、庙、和尚、故事,方法内容如下

              图29

  到了和尚讲故事后,要做的事情 跟方法里的事情一样,那么可以调用方法自己

            图30

  那么当用例运行方法“山、庙、和尚、故事”,会先运行1~4行,到第5行的时候,又运行方法“山、庙、和尚、故事”,又再运行1~4行,然后再运行方法“山、庙、和尚、故事”……因为没有跳出的结束标志,因此就会无限循环运行,结果如下:

  PS:报错为RF设置的递归阙值,递归的方法运行次数达到阙值时就报错。

                    图31

  回过来看我们的json串对比③,它跟故事类似,因此我们也可以用递归的方法,区别在于要有结束的标志。

  新建一个方法:判断两个json是否相等

  方法前面即为前面①②实现的内容

                                图32

  获取到子json后,子json又重复前面的步骤,如下图在for循环下,运行方法自己:则可以一直重复①②,直到找不到子json,${child_jsons_list}为空,for循环跳过,不再运行方法自己。

                                图33

  ④找不到子json后,开始判断当前节点的json串是否相等

                                图34

  方法:断言两个dict或list相等

                                图35

  假设最后一层jsons是json_last,那么倒二层可能是这样的[json_last1,json_last2],也有可能是{"key1":"value1","json_last":json_last}

  在倒二层for循环中,运行方法”判断两个json是否相等“,把所有的json_last判断完后,则for循环执行结束,开始执行方法“断言两个dict或list相等”,即判断倒二层的json是否相等。

  以此类推,会逐层往上,完整的判断整个json。

  以上,实现了递归判断两个json串是否相等,里面具体的提示可以优化,也可以增加入参,对指定节点进行判断,还有这么判断非常耗时,在自动化中可以在前面先直接用should be equal来判断,不等时再执行该方法调试错误。可优化的东西比较多,这里就不一一写了。

上一篇  9-1、大型项目的接口自动化实践记录----数据库结果、JSON对比

9-2、大型项目的接口自动化实践记录----递归判断两个json串是否相等的更多相关文章

  1. 9-1、大型项目的接口自动化实践记录----数据库结果、JSON对比

    上一篇写了如何从DB获取预期.实际结果,这一篇分别对不同情况说下怎么进行对比. PS:这部分在JSON对比中也适用. 1.结果只有一张表,只有一条数据 数据格式:因为返回的是dicts_list的格式 ...

  2. 8、大型项目的接口自动化实践记录----DB分别获取预期结果、实际结果

    上一篇实现数据分离升级版--从DB获取数据,以及对应的请求实现,作为一个case,还缺少了预期结果与实际结果的获取及对比.因为前面的文章已经说过接口返回值的获取及对比,所以这篇不说这块了,这篇说一下D ...

  3. 3、大型项目的接口自动化实践记录----开放API练习

    开始做实际项目前,先拿个网上的简单API练下手 一.API说明: 接口信息 接口名:京东获取单个商品价格 地址:http://p.3.cn/prices/mgets 入参:skuids=J_商品ID& ...

  4. 2、大型项目的接口自动化实践记录--接口测试简介及RequestsLibrary关键字简介

    1.接口测试简介 1)先简单介绍下接口测试,那么什么是接口测试呢? 百科的回答:接口测试是测试系统组件间接口的一种测试.接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点. 看起来有 ...

  5. 1、大型项目的接口自动化实践记录--robotframework环境搭建

    因为人力.团队技术问题,选用robotframework来做自动化,首先说下环境搭建 齐涛道长的入门教程非常棒:http://blog.csdn.net/tulituqi/article/detail ...

  6. 接口自动化平台搭建(二),搭建django项目与接口自动化平台的由来与功能特征

    1.创建django项目 a.使用命令创建,安装完django之后就有django-admin命令了,执行命令创建即可,命令如下: django-admin startproject my_djang ...

  7. python入门以及接口自动化实践

    一.Python入门必备基础语法# 标识符:python中我们自己命名的都是标识符# 项目名 包名 模块名# 变量名 函数名 类名# 1:字母 下划线 数字组成 命名的时候不能以数字开头# 2:见名知 ...

  8. 19 | 真实的战场:如何在大型项目中设计GUI自动化测试策略

  9. python+pytest接口自动化(16)-接口自动化项目中日志的使用 (使用loguru模块)

    通过上篇文章日志管理模块loguru简介,我们已经知道了loguru日志记录模块的简单使用.在自动化测试项目中,一般都需要通过记录日志的方式来确定项目运行的状态及结果,以方便定位问题. 这篇文章我们使 ...

随机推荐

  1. 【朝花夕拾】Android自定义View篇之(一)View绘制流程

    前言 转载请申明转自[https://www.cnblogs.com/andy-songwei/p/10955062.html]谢谢! 自定义View.多线程.网络,被认为是Android开发者必须牢 ...

  2. 搭建CentOS 7本地源仓库

    CentOS 7离线包及其依赖 推荐使用yumdownloader --resolve --destdir=path python-pip,--resolve下载所有依赖,--destdir指定软件包 ...

  3. C# Redis分布式锁(基于ServiceStack.Redis)

    相关的文章其实不少,我也从中受益不少,但是还是想自己梳理一下,毕竟自己写的更走心! 首先给出一个拓展类,通过拓展方法实现加锁和解锁. 注:之所以增加拓展方法,是因为合理使用拓展类(方法),可以让程序更 ...

  4. Effective Java - 构造器私有、枚举和单例

    目录 饿汉式单例 静态常量 静态代码块 懒汉式单例 尝试加锁 同步代码块 双重检查 静态内部类单例 枚举单例 Singleton 是指仅仅被实例化一次的类.Singleton代表了无状态的对象像是方法 ...

  5. DataBinding的用法

    一.基本介绍 DataBinding数据绑定库是一种支持库,借助该库,可以使用声明性格式(而非程序化地)将布局中的界面组件绑定到应用中的数据源.这是官方给出的介绍. 那么为什么要使用DataBindi ...

  6. Codeforces 777E:Hanoi Factory(贪心+栈)

    http://codeforces.com/problemset/problem/777/E 题意:给出n个环状圆柱,每个圆环有一个内半径a,外半径b,和高度h,只有外半径bj <= bi并且b ...

  7. leetcode笔记 动态规划在字符串匹配中的应用

    目录 leetcode笔记 动态规划在字符串匹配中的应用 0 参考文献 1. [10. Regular Expression Matching] 1.1 题目 1.2 思路 && 解题 ...

  8. 深入理解C#的装箱和拆箱

    个人理解(本质): 封箱是把值类型转换为引用类型 拆箱是把引用类型转换为值类型 封箱是把值类型转换为System.Object类型,或者转换为由值类型实现的接口类型: 例如: struct Mystr ...

  9. XAML与C#与WPF三者到底有什么关系?

    XAML是.NET体系开发程序或者网页时前台编程的一种布局方式或者说开发语言,可以比较自由的用标签的方式进行布局,借鉴了HTML和XML等语言的风格,并且加入了一些动画等的实现.C#则是后台逻辑开发用 ...

  10. 使用@Transactional注意的问题

    @Transactional 基本原理概述 在应用系统调用声明@Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据@ ...