zoukankan      html  css  js  c++  java
  • 测试数据管理带来的效率提升

    对于测试人员,说到数据管理,恐怕都会皱起眉头。测试的很大一部分时间其实无非就是在和数据打交道,除了测试的时候,有时开发或者其他业务的同事也会跑过来说:XX,麻烦帮我造下啥啥数据吧。这个时候,若没有提前做好数据管理,而需要一个个的临时准备,是不是恨不得抛一句:你自己不会造呀,我又不是造数据的。但是理智告诉我们,这样说你就输了呀,测试就是应该最懂造数据的。

      这个时候,啥TD事务呀,数据工厂呀就应运而生了。不过,这些大多都是给非本产品的人用的,目的是便于他人的操作,也为了减少自身被咨询的工作量。那么,有没有想过,在我们自己做测试的时候,自己给自己做一份数据管理呢?对于一些业务逻辑复杂的产品来说,需要校验每一步的结果,数据管理不是很好做,而且需要的数据量也不大,意义或许也不是特别大。但对于业务逻辑简单,涉及数据又比较多的产品来言,数据管理将能起到很好的作用。

      在淘宝交易中心、收藏夹和关联推荐3个产品都呆过一段时间,这种感受就尤为深刻。对于像收藏夹和关联推荐产品来讲,业务复杂度也就是orcale相对简单,但是涉及的数据量却比较多,对于这种业务的测试,每一次都要单独去花很长的时间准备数据,是一件即繁琐又重复的工作,不仅降低了测试的效率,同时由于各人准备各人的数据,数据维护成本将会非常大。这种情况随着咱们测试技能的提升,基本用接口测试的时候显得尤为明显。

      那么,怎么样做数据管理呢?怎么样的数据管理能为大家所用,为大家提高工作效率呢?下面以关联推荐测试为例,来共同探讨下数据管理。

      一、需求背景

      之前,数据准备的方式是写用例的人各自准备各自的数据,并且来一个日常准备一次,这样的方式,必定造成以下的困扰。

      第一,随着用例越来越多,每个人都用自己的数据进行测试,数据维护成本越来越大(很多时候用例失败都是数据问题)。

      第二,测试人员来一个日常就要准备一次数据,甚至每个用例都要准备数据,极大地降低了测试效率。

    为了解决以上难题,设计了一套数据管理方案。测试人员只需要调用以下公共方法,即可获得想要的数据。它使工程里的数据全部集中在一起,便于后续的维护和管理;它减少了测试人员的重复工作,业务与数据隔离,不需要每个日常为准备数据而花费过多的时间。它还带来了一个额外的收获——提高开发自测积极性。众所周知,对于开发自测,最头疼的莫过于数据管理了,统一数据管理之后,将能很好的带动开发自测的积极性,对于一般日常,我们完全可以放开让开发自测,解放测试资源投入到算法测试,系统测试等更重要的工作中。

      一句话总结就是,使数据管理面向对象化、业务场景和数据隔离。

      二、关联推荐数据存储介绍

      关联推荐的数据存储方式比较特殊,目前为止有4种存储方式,分别是:Mysql、OceanBase、Vsearch、Treasure,使用的最多的是Treasure。在Treasure中,数据存储格式是app,key->value的存储格式。每一份数据都有一个唯一标识的app,每个app里存储着对应的数据,以key->value格式,如userId->itemId,itemId,...。这份数据有可能是用户购买意向宝贝,也有可能是用户肯定不喜欢的宝贝,这都取决于它的app是多少,每个app都对应了这份数据的意义,对应了相应的使用场景。也就是说使用于不同场景的数据,很多数据格式是一样的,都是userId->itemId,itemId,...或者是sellerId->cid,cid,...等,对于线上场景来讲,数据格式一样,但是用于不同的场景必然数据也是不同的,但是对于我们接口测试来讲,我们并不关心这个数据的真实性,不同场景的数据只要数据格式一样,都可以使用同一份数据。例如app43和app44,它们的数据格式一模一样,但是用在了不同的场景,实际线上的数据计算方式和结果都是不一样的,但是我们测试的时候用同样的数据一点问题也没有,因此,每个日常都独立准备数据是完全没有必要的。除此之外,现在场景优化的日常很多,如果有了数据管理,数据就可以很方便的复用。无论是开发还是其他业务的同学找你造数据,都变得得心应手,小菜一碟。

    三、技术方案

      方案1  

      为最大程度地减少测试人员与数据的接触,方案1几乎不需要测试人员知道用的是什么数据,什么格式,只需要传入app、key和需要的数量,即可得到想要的数据。数据管理的步骤如下:

           Step1:测试人员输入app,key的格式(也可以直接输入key值),需要的value个数count,每个value中多元素的个数count2[];

           Step2:根据传入的key格式会返回一个key;

           Step3:根据传入的app和key,选择相应的value;

           Step4:updateTreasure(app,key,value);

           Value中的数据由基础数据(itemIds,spuIds,cids,…)提供,在这些基础数据中又提供了一些方法,如itemIds中,getItem(count)是获取从0到count个的宝贝,getItem(startIndex,endIndex)是获取第startIndex到endIndex个宝贝,genInvaildItem(count)是获取count个失效的宝贝。如果需要自己传入value,则可以将Step3改为按value中元素的顺序传入所需的数据即可。数据管理逻辑图如图3-1。

      

                                            图3-1 方案1 数据管理逻辑

    显而易见的是,这种方案的缺点是测试人员完全不知道数据,没有安全感,且随着日常的不断增多(app也增多),选择value的判断语句会越来越长,不利于维护,并且整个准备的系统过于复杂,实现起来较困难,维护成本高。

          鉴于以上的原因,又设计了方案2。

    方案2 

    相对于方案1,方案2需要测试人员明确地知道所需数据的格式,数据管理将有可能用到的key和value的格式数据都已经准备好,测试人员只需按需调用公共方法即可获取所需数据。该方案数据管理步骤如下:

           Step1:选择需要的key;

           Step2:选择需要的value;

           Step3:updateTreasure(app,key,value);

    其中key和value的数据可以用数据管理默认的数据,也可以自己输入需要的数据,同方案1,key和value中的数据都是由基础数据提供。数据管理逻辑图如图3-2。

           可见,此方案实现简单,测试人员也可以对所调用的数据做到心中有数,即便后面需要新的数据格式,也只需要再增加一个方法即可。

                          图3-2 方案2数据管理逻辑图

    四、代码实现

      4.1 基础数据

              图4-1 基础数据

    基础数据中,保存的是各种底层数据,以供key和value方法调用,测试人员也可以直接从基础数据中获取想要的数据。有了这些数据之后,写用例的时候就不必再临时造数据,并且当有因为数据问题而造成脚本失败的情况,也非常容易排查。以itemId为例:

              图4-2 基础数据itemId

    在这份基础数据中,给出了3位数的宝贝ID,并给出了下架、删除、CC、优惠等特殊宝贝,还有获取这些宝贝的方法,可以获取指定区间的宝贝,可以获取指定类型的宝贝。下述框框中,列举了几个方法:

    其他基础数据的形式与此类似,使用者若需要更多或者更特殊的数据,都可以在这个基础上进行添加。

    4.2 解析类

               图4-3 解析类

    解析类的作用主要是在对key和value进行组合的时候用的,对基础数据,或是用户传进来的数据以某种分隔符进行拆分或重组。如下面这段解析代码就是对传入的List数据以期望的分隔符进行重组,返回的String类型。除了该方法,解析类里还有其他一些拆分重组的方法,如果使用者有需要,也可以添加自己想要的方法。

    4.3 key

                    图4-4 key

    这里的key包含的是那些需要组合的key,只有一个数据的key使用者可以直接从基础数据中获取。下面以cpv为例,说明一下怎么组装key。由下述代码中可知,key中的数据也是调用基础数据得到的,值得指出的是,在每份基础数据中都有一份数据是特别给key用的,其他数据是给value调用的,无论是key方法里调用还是使用者都应该注意这一点,以免key值和value中的值重复。

      4.4 value

                     图4-5 value

    Value已经包含了目前已有的所有组合value,同key,单个数据的value可以通过直接调用基础数据获得。

      Value中需要传入的数据,如果使用者没有特殊需求,都可以使用默认值。代码会根据传入的count和count2进行分配,组合到你想要的数据,这时除了count和count2外,其他参数都可以传入null。当然,如果你需要自己传入数据也没有问题,只要传入的数据个数和count、count2是匹配的就可以,代码会自动给你分配好数据,并将组合好的value返回给你。

    这里以CidItemid为例,说明value是怎么组合的。

    /**

         * value格式:cid:itemid^itemid^...,cid:itemid^itemid^...,...或cid:itemid,itemid,...,cid:itemid,itemid,...,...item之间的分隔符由传入决定,默认为^

         * 涉及的app有7,88

         * 调用示例在detail页面浏览了还浏览(http)用例里

         * @param cids 类目ID,使用默认值可传入null

         * @param items 宝贝ID,使用默认值可传入null

         * @param count value个数

         * @param count2 value中某个元素多个,多个的个数count2[0]表示第一个value中多元素的个数,count2[1]表示第二个value中多元素的个数,依次类推。

         * @return value

         * @throws Exception

         */

    public static String cidItemid(List<String> cids, List<String> items, int count,int[]count2, String sep) throws Exception{

           if(count != count2.length){

    throw new Exception("value的个数和用来标识每个value中多个元素个数的数组长度必须相同!");

           }

           int k = 0;

           for(int i=0; i<count; i++){

               k = k + count2[i];

           }

           List<String> Cid = Cids.getCids(count);

           List<String> itemids = ItemIds.getItemIds(k);

           List<String> ITEM = new ArrayList<String>();

           String value = "";

           String[] imp;//中间结果,用户存放每个value中的items

           imp = new String[count];   

           String[] item_imp;

           item_imp = new String[count];

            if(null != cids)

               Cid = cids;

           if(null != items)

               itemids = items;    

           if(k != itemids.size()){

               throw new Exception("传入的itemid个数和需要的个数不相同!");

           }

           int a = 0;

           int c = 0;     

      for(int i=0; i<count; i++){

               item_imp[i] = "";

               c = c + count2[i];

               for(int j=a; j<itemids.size();j++){

                  item_imp[i] = item_imp[i] + "," + itemids.get(j);

                  a ++;

                  if(a == c){

                      break;

                  }

               }

          ITEM = ParameterConfirm.expectObjectsTolist(item_imp[i]);

               if(null != sep){

                  imp[i] = Parse.chars(ITEM,sep);

               }else{

                  imp[i] = Parse.chars(ITEM,"^");

                }         

           }

           for(int i=0; i<count; i++){

               if(i==(count-1)){

                  value = value + Cid.get(i) + ":" + imp[i];

               }else{

                  value = value + Cid.get(i) + ":" + imp[i] + ",";

               }

           }

           return value;    

        }

    五、使用说明 

      5.1 使用说明

        1、采用默认值

      首先获取key,如key = Cpv.cp_v(null,null,null);

    然后获取相应的value,如value = CidItemidValue.cidItemid(null, null, 3,{1,2,3},”,”);

    最后将数据存储进treasure。updateTreasure(app,key,value);

      2、自己传入值

          首先构造key,如 key = Cpv.cp_v(Cids.cid_key,Pids.pid_key,Vids.vid_key);

          然后构造value,如 value = CidItemidValue.cidItemid(Cids.getCids(3), ItemIds.getItemIds(6), 3,{1,2,3},”,”);

    最后将数据存储进treasure。updateTreasure(app,key,value);

    5.2 示例解析 

      下面以购物车猜你喜欢接口为例,说明具体怎么使用数据管理。

     Setp1:获取key。这里可是单个数据组成,则调用基础数据,如果是多个数据组成,则调用生成key的方法;

      Step2:定义好count2,即每个value中多个元素的个数;

      Step3:通过count和count2获得value;

      Step4:将数据存储入treasure;

      Step5:调用接口;

      Step6:获取预期值。由于value中的数据都由基础数据提供,所以不难得到预期值;

      Step7:预期值与实际值校验。

      最后treasure中的数据是:key:2011615130,value: 50010388:5:1500010005607;50011153:5:1500010005610,1500010005641,1500010005642;162116:5:1500006427759,1500005566213,1500005566211,1500010418250,1500010418207;50008901:5:1500010418247,1500010418204,1500010418162,1500007100551,1500010417767,1500005546143;50011159:5:1500010417129,1500010415006

      六、总结 

      经过上述的介绍,大家对数据管理的方便应该可以感受比较深切。对于推荐系统,其特殊的key->value存储格式以及数据复用性,推荐系统逻辑的单一性,使得数据管理占据接口测试的很大一部分时间,因此公共的数据管理方法就显得特别需要。其实,对于业务场景不复杂的产品,数据管理都会起到比较好的作用,比如收藏夹也可以做一个宝贝和店铺的数据管理,将会极大的提高接口测试效率。

      目前,数据管理基本涵盖了现有的key和value,随着新业务的增多,相应的key和value可能也需要随之增加。不过,以后的数据格式会越来越统一,数据管理的维护成本也会随之降低,届时,数据管理的功效将会显而易见。

  • 相关阅读:
    c++笔记--数组对象、vector对象和构造函数
    马加爵之歌
    周末有同学要来
    IQ
    [转]JavaScript中typeof 讲解
    【转】JS兼容Firefox
    firefox与ie 的javascript区别
    关于委托(转)
    经典常用的javascript代码收藏
    关于DataList使用DropDownList的分页实现 技巧实例源码
  • 原文地址:https://www.cnblogs.com/taobaomercury/p/2597308.html
Copyright © 2011-2022 走看看