一、常规数据分离
上一篇,实现了订单新增接口的请求,这块的核心业务case200+,因此要做下数据分离,先提取下方法:
1、新建resource:订单新增接口.txt,在resource下新建关键字订单新增接口、变量${URI},${URI}值为订单新增接口对应的URI,即/c/contractsign/addcontract
![](https://upload-images.jianshu.io/upload_images/11558001-dec5a514edf1aa63.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2、订单新增接口
![](https://upload-images.jianshu.io/upload_images/11558001-5bcc644b2439bcd0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
如上图,提取关键字,后面case数据,只需要维护${port} | ${username} | ${password} | ${data}
因为登录属于前置条件,因此放到setup中,订单新增接口只保留它自己的内容
![](https://upload-images.jianshu.io/upload_images/11558001-5d8949fb9e48a252.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
如下图,改完后,在case层,则只需要维护登录的信息、data
![](https://upload-images.jianshu.io/upload_images/11558001-2e31a9cd3553e176.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
PS:登录方法中,在最后需要加,这样case中cookies才可以用
![](https://upload-images.jianshu.io/upload_images/11558001-cb582ba428759ebc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
因此常规数据分离如下图:
![](https://upload-images.jianshu.io/upload_images/11558001-5161731eb4234755.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
完成了数据分离,则开始专注维护测试数据
![](https://upload-images.jianshu.io/upload_images/11558001-f3f13eae163a0693.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
维护下来,发现工作量很大(主要是其中data部分,可见上图滚动条),而且很容易出错。因为其中很多字段关联性强,且有值为json串,如果要保证正确性,则需要通过前端操作,抓包获取数据,这样工作量巨大。以一个case10分钟为例,需要超过2000+分钟,这只是系统的一个模块而已,想想功能要有所变动,增加字段,那维护量就太大了。
二、数据分离升级版----需要解决的问题
头脑风暴:每次新功能或者功能变动,都会有对应的手工测试,而手工测试完,在DB中都会留下对应的测试数据。如果可以用特定规则,获取到这些数据,在case层只需要维护如下内容,那么数据的维护工作就很低了。
数据库名:数据来源库
数据主键:要取的数据的主键
端口号:要在哪个环境做接口请求
![](https://upload-images.jianshu.io/upload_images/11558001-6df19cd5ee009c27.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
方案思考:
1、封装对应的数据获取逻辑,根据数据主键、来源库获取对应的数据
2、处理获取到的数据中的唯一值、特殊值等
3、最后根据接口字段与DB字段的映射关系,获取到对应的data
如下图:
![](https://upload-images.jianshu.io/upload_images/11558001-f1ff43db9b38bd75.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
这样在case层则只需要维护用例、数据主键、来源库,就可以获取到对应的data,手工测试过的数据,就可以快速复用了。
需要解决:
1、从DB获取数据
2、功能对应的数据库表整理
3、数据获取后,一些字段的值需要修改
4、接口字段与DB字段的映射
着手去解决:
1、从DB获取数据:
1)先打通数据库
![](https://upload-images.jianshu.io/upload_images/11558001-f88527dba4dffedc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
在suite文件处,先导入库DatabaseLibrary、Collections、String
实现连接数据库,查询:
![](https://upload-images.jianshu.io/upload_images/11558001-87709380492c2447.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
①连接数据库:Connect To Database Using Custom Params
Driver=对应装的ODBC版本
Server=数据库地址(一般是数据库服务器IP)
Port=端口号
Database=要连接的数据库name
User=用户名
Password=密码
②查询:Query
③打印查询结果:log ${data}
![](https://upload-images.jianshu.io/upload_images/11558001-fd68dd195eef1049.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
可以在日志可以看到成功获取到了数据,数据格式为由元组组成的list:[(),()]
2)封装对应方法
①连接数据库:
![](https://upload-images.jianshu.io/upload_images/11558001-57f06060337d21f6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](https://upload-images.jianshu.io/upload_images/11558001-886bddaf904a6dcd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
假设常用的环境对应的数据库有三个,分别为DB1、DB2、DB3,每个库都有对应的用户名密码等信息,则配置如图10,变量名以num结尾,第一个库的信息为0,第二个为1……。
连接数据库的方法,根据传入的库名,设置变量${num},然后根据${num}连接对应的数据库。
②查询数据:
上面看到,用Query可以查询到对应的数据,但是格式是元祖组成的list,不太方便后面的使用,如果数据是字段名+value的键值对,即[dict,dict,……],则会比较方便使用,因此我们再做下封装。
A、首先根据查询语句获取keys(字段名)
![](https://upload-images.jianshu.io/upload_images/11558001-3e20fe5bbc1bc62c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
B、然后根据查询语句获取keys及datas
![](https://upload-images.jianshu.io/upload_images/11558001-4dd7ea98f541ec4c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
C、再然后keys、values拼接成dict
![](https://upload-images.jianshu.io/upload_images/11558001-f0879d6d4dcd5fbc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
PS:有简单的写法${dict_back} Evaluate dict(zip(${keys},${values})),但是因为我们的数据会有特殊值,该写法会出错,因此没有用。
D、接着用获取的keys、datas组成dicts_list
![](https://upload-images.jianshu.io/upload_images/11558001-8a70a46bfaf63846.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
E、最后根据查询语句,获取数据dict集,拼接成dicts_list
![](https://upload-images.jianshu.io/upload_images/11558001-681773d7fde05f8f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
好处:后面使用方便
缺点:性能变差(因此大数据时不使用)
2、功能对应的数据库表整理
考虑预发布环境操作的频率会较低,因此在预发布环境开放SQL日志
然后在linux服务器上,对应的目录下,加一个脚本,内容如下,其中mysql-bin.index为二进制日志汇总
脚本功能:根据起止时间,过滤出insert、update、delete开头的语句,其中mysql-bin.index为日志汇总,这样用户在预发布环境操作后,可以根据起止时间,过滤出对应的SQL语句
![](https://upload-images.jianshu.io/upload_images/11558001-55c44e547b77acce.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
为了获取SQL执行语句,还要专门上linux服务器执行命令,这样比较麻烦,因此在RF上去实现下:
导入SSHLibrary
![](https://upload-images.jianshu.io/upload_images/11558001-0d2114aafb3b47ef.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
通过SSH连接到linux服务器,入参为起止时间,执行linux服务器上的脚本,更新sqllog文件
![](https://upload-images.jianshu.io/upload_images/11558001-3feaea036a986cce.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
接着把linux服务器上,对应的sqllog文件下载到本地指定路径
PS:Get Tables是自己封装的方法,作用是再根据下载下来的文件,过滤出对应的表名并去重。
![](https://upload-images.jianshu.io/upload_images/11558001-419c6e07b4690916.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
3、修改字段的值
举个栗子,假设一个单据对应多条明细,单据id为100,我们通过方法”根据查询语句,获取数据dict集,拼接成dicts_list“ + ”SELECT * FROM 明细表 WHERE parentid=100“,查询到结果如下:
[{u'name': u'test1', u'parentid': u'100'}, {u'name': u'test2', u'parentid': u'100'}]
其中parentid为明细对应的主表id,我们在RF这边模拟构造下这个数据
![](https://upload-images.jianshu.io/upload_images/11558001-5acc560d2de8c005.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](https://upload-images.jianshu.io/upload_images/11558001-1916de2074b77d97.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
当我们从DB获取到主表及明细表的数据,当做测试数据使用时,那么会发现,新增主表数据的时候,有新id生成,假设为101,那么新增明细的时候,对应的parentid需要改成101。可以通过for循环遍历list,把其中的parentid改掉,如下图。
![](https://upload-images.jianshu.io/upload_images/11558001-9747e06e0001fa53.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
结果如下,可以看到parentid都变成101了。
![](https://upload-images.jianshu.io/upload_images/11558001-4bf6ef6938f0889a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
4、接口字段与DB字段的映射
![](https://upload-images.jianshu.io/upload_images/11558001-3d2e6ab4992258d6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
映射关系如上图,其中${data_all}、${current_data_all}为前面dicts_list中的dict,因此如${data_all['id']}可以取到对应的id值,传给接口的id字段。
三、数据分离升级版----订单接口实现
我们以逆推的方式,去看这个过程实现
1、首先新建合同和订单新签目录,在目录下新建DB与接口映射关系Resource,在该Resource下,放图9中的func3,根据映射关系、数据,获取data。
1)在Resource下新建方法,获取cdn订单新增data。
![](https://upload-images.jianshu.io/upload_images/11558001-6e6cf4cf065fe077.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
方法内容如下,新建${data},把接口抓到的所需要的入参都add上。
![](https://upload-images.jianshu.io/upload_images/11558001-876038e35e36c18a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2)观察字段来源于哪张表的字段,发现分别来源于contract、paycls、pay表,还有些特殊字段如cdnitemjson,它的值是一个json串,相当于子data串,因为这层做的是data这层的映射,因此先不管它。
假设我们已经取到了对应几张表的data及几个json串,并且已经处理过,则映射关系如下图:
![](https://upload-images.jianshu.io/upload_images/11558001-126149ad1a7464d7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
3)同样的,新建获取对应的appditemjson、cdnitemjson、speedjson
![](https://upload-images.jianshu.io/upload_images/11558001-77458a540bf19c82.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
与主data不一样的是,这些json串,数量可能为0~N,因此入参为dicts_list,映射关系写法如下图,在for循环中做对应的赋值(这里只写两个字段做下说明)。
![](https://upload-images.jianshu.io/upload_images/11558001-c6b50658782bf177.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2、新建Resource:DATA_来源,在下面放图9中的func1,用于从DB获取数据
1)新建方法,获取对应的数据
![](https://upload-images.jianshu.io/upload_images/11558001-62e32629e6000b46.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2)因为我们要查的数据不多,因此直接用了select *,主data信息都是一条,返回的是dict,所以返回list[0]
![](https://upload-images.jianshu.io/upload_images/11558001-60c4786d77d5a0af.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
对应的json串数据,数据可能性0~N条,因此返回dicts_list
![](https://upload-images.jianshu.io/upload_images/11558001-5503443458f7f8e1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
3、新建Resource:DATA_处理,在下面放图9中的func2,前面获取到的数据,还不能直接使用,需要对其中的一些特殊字段进行处理。
1)新建方法,处理对应的数据
![](https://upload-images.jianshu.io/upload_images/11558001-0fb176d074d9e134.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2)下图为json的字段处理举例,其中接口请求中字段为id,但是DB中则不是,act字段为固定值,有的字段可能会是随机数等。
![](https://upload-images.jianshu.io/upload_images/11558001-33a3f43192927522.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
4、新建Resource:操作步骤_DATA,引用前面3个Resource
![](https://upload-images.jianshu.io/upload_images/11558001-d4fae211941962ba.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
1)在目录下,新建方法订单新增data,实现获取、处理、映射成接口可用data的过程
![](https://upload-images.jianshu.io/upload_images/11558001-ff88ae0d343b1e3b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2)方法内容如下,将前面的过程串联起来,发现我们只需要传数据主键,就可以获取到对应的data了。
![](https://upload-images.jianshu.io/upload_images/11558001-c6107f6eec5567a9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](https://upload-images.jianshu.io/upload_images/11558001-3f8d7d4b977b5c13.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
5、再跟前面的Action等关联上,新建Resource:操作步骤,引用操作步骤_DATA。
![](https://upload-images.jianshu.io/upload_images/11558001-66a915d225ddcd46.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](https://upload-images.jianshu.io/upload_images/11558001-d0b82439d064a997.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
1)新增方法订单新增,即操作步骤的ACTION
![](https://upload-images.jianshu.io/upload_images/11558001-edd632597ea79c63.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
6、新建Resource:订单新增FLOW,引用”操作步骤“
![](https://upload-images.jianshu.io/upload_images/11558001-90cf1dbecc9a2eb8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](https://upload-images.jianshu.io/upload_images/11558001-3349aa354dcc4353.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
1)新增方法订单新增FLOW,连接数据库,执行操作步骤,实际结果与预期结果对比
![](https://upload-images.jianshu.io/upload_images/11558001-656b16a30b505c65.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
7、再新建suite,引用订单新增FLOW,在suite下新建case,则实现了图8中所期望的。