• 0
  • 0
分享

  本文以笔者当前使用的自动化测试项目为例,浅谈分层设计的思路,不涉及到具体的代码细节和某个框架的实现原理,重点关注在分层前后的使用对比,可能会以一些伪代码为例来说明举例。

  接口测试三要素:

  ·参数构造

  · 发起请求,获取响应

  · 校验结果

  一、原始状态

  当我们的用例没有进行分层设计的时候,只能算是一个“苗条式”的脚本。以一个后台创建商品活动的场景为例,大概流程是这样的(默认已经是登录状态下):

  创建商品-创建分类-创建优惠券-创建活动

  要进行接口测试的话,按照接口测试的三要素来进行,具体的效果如下:

  参数构造:

      createCommodityParams = {
          "input": {
              "title": "活动商品",
              "subtitle": "",
              "brand": "",
              "categoryLevel1Code": "12",
              "categoryLevel2Code": "1312",
              "categoryLevel3Code": "131211",
              "detail": [
                  {
                      "uri": "ecommerce/1118d9.jpg",
                      "type": 0
                  }
              ],
              "installInfo": {
                  "installType": 1,
                  "installFee": null
              },
              "pictureList": [
                  {
                      "uri": "ecommerce/222.jpg",
                      "main": true
                  }
              ],
              "postageInfo": {
                  "postageType": 2,
                  "postageFee": 1,
                  "postageId": null
              },
              "sellerDefinedCode": "",
              "publish": 1,
              "skuList": [
                  {
                      "skuCode": "",
                      "externalSkuCode": "",
                      "price": 1,
                      "retailPrice": 6,
                      "stock": 100,
                      "weight": 0,
                      "suggestPrice": 0,
                      "skuAttrValueList": [
                          {
                              "attrCode": "COLOR",
                              "attrName": "颜色",
                              "attrValue": "绿色",
                              "attrValueId": "1001"
                          }
                      ]
                  }
              ],
              "jumpSwitch":false,
              "recommendCommodityCodeList": [],
              "recommendFittingCodeList": [],
              "mallCode": "8h4xxx"
          }
      }
      createCategoryParams = {......}
      createCouponParams = {......}
      createPublicityParams = {......}
      publishCommodityParams = {......}
      publishPublicityParams = {......}
      createCommodityParams["input"]["title"] = "autoTest" + str(time.time())
      createCommodityParams["input"]["mallCode"] = self.mallCode
      createCommodityParams["input"]["skuList"][0]["price"] = random.randint(1,10)
      createCategoryParams["input"]["categoryName"] = "autoTestCategory" + str(time.time())
      createCouponParams。。。
      createPublicityParams。。。
      publishCommodityParams。。。
      publishPublicityParams。。。
      # 2、发起请求,获取响应
       # 创建商品并获取商品code
      createCommodityRes = api.getUrl("testApi.create.commodity").post.params(createCommodityParams)
      commodityCode = createCommodityRes["commodityCode"]
       # 创建分类并获取分类code
      createCategoryRes = api.getUrl("testApi.create.category").post.params(createCategoryParams)
      categoryCode = createCategoryRes["categoryCode"]
       # 创建优惠券并获取优惠券code
      createCouponRes = api.getUrl("testApi.create.coupon").post.params(createCouponParams)
      couponCode = createCouponRes["couponCode"]
       # 创建活动并关联商品,绑定优惠券,设置分类
      createPublicityParams["input"]["commodityCode"] = commodityCode
      createPublicityParams["input"]["categoryCode"] = categoryCode
      createPublicityParams["input"]["couponCode"] = couponCode
      createPublicityRes = api.getUrl("testApi.create.publicity").post.params(createPublicityParams)
      # 结果校验(断言)
      assert.equal(createPublicityRes["code"], 0)
      assert.equal(createPublicityRes["publicityName"], createPublicityParams["publicityName"])

      。。。

  按照上面的写法,对于单个脚本的调式来说或许可以,但是一旦用例的数量和复杂程度积累起来后,其维护成本将是巨大的,或者可以说不具备可维护性。

  弊端说明:

  ·可读性差,所有的处理都放在一起,代码量大,不简洁直观

  · 灵活性差,参数写死在脚本,适用用例范围小

  · 复用性差,如果其他用例需要同样或类似的步骤,需要重新写一份

  · 维护性差,如果接口有任何改动,那么所有涉及到此接口的脚本都需要一一修改

  例如:随着用例场景的增加,就可能会出现下面这种情况。

1-1.png

  按照原始的模式,我们就需要些3个脚本文件分别来描述着3个场景,并且创建商品_API、创建分类_API、创建优惠券_API在场景1,2,3中均出现了;上架商品_API在场景2,3中均出现。由此我们完全可以预见到,当几百上千的用例场景出现后,这种形式是没有维护性可言的。

  二、进化历程

  因此我们依照着痛点,以最开始的原始状态为例,对用例进行分层改造,来看看进化后的状态。

  1、API 定义层

  我们编程的时候会将一些重复的代码进行封装使用,那么这里依然可以借用这种思想,我们将 API 的定义单独抽离,单独定义。

  我们期望的效果是这样的:

1-2.png

1-3.png

  提前将API的定义放在一层,供用例场景引用,这样当接口有任何修改时,我们只需要修改API definition层即可。

  实例演示

  对应着上面的demo,我们就是需要做如下抽离:

  class APIDefinition:'''创建商品API定义 createCommodityParams: 创建商品接口入参 return:创建商品接口响应结果 ''' def createCommodityRequest(createCommodityParams): return api.getUrl("testApi.create.commodity").post.params(createCommodityParams)

  '''
       创建分类API定义
       createCategoryParams: 创建分类接口入参
       return:创建分类接口响应结果
       '''
       def createCategoryRequest(createCategoryParams)
        return api.getUrl("testApi.create.category").post.params(createCategoryParams)
       # 创建优惠券接口定义
       def createCouponRequest(createCouponParams)
        return api.getUrl("testApi.create.coupon").post.params(createCouponParams)
       # 创建活动接口定义
       def createPublicityRequest(createPublicityParams)
        return api.getUrl("testApi.create.publicity").post.params(createPublicityParams)
       # ...其余省略

  2、Service 层

  上面我们已经将接口的定义抽离出来,解决了 API 重复定义的问题,但是再继续分析会发现有一个问题依然没有解决,就是场景的复用性.

  再看刚才的图:

1-4.png

1-5.png

  3个场景中都有重复的步骤,类似创建商品、创建分类、创建优惠券这些,并且这些步骤都是一个个API的组合,一个步骤对应一个API,在各个步骤之间还会有数据的处理与传递,为了解决这些问题,将对场景再次做抽离,这里我称之为 service层。

  这一层之所以叫做?service(服务)层,是因为它的作用是用来提供测试用例所需要的各种“服务”,好比参数构建、接口请求、数据处理、测试步骤。

  用下图先来看分层的目标:

1-6.png

  我们希望将常用的测试场景步骤封装至service层中,供用例场景调用,增加复用性,也可以理解为测试用例的前置处理;

  但是这里还是有一点小问题,就是service层的东西太多太杂,有些场景步骤可能只适用于我当前的项目用例,在实际的工作中,各个系统间是相互依赖的,前台APP的测试很大可能就依赖后台创建作为前置条件

  好比我在APP端只要商品和分类,可能只想创建商品和分类,并不想创建优惠券,这个时候service层就没有适用的场景步骤供调用,那么我就需要根据自己的需要重新封装;可是对于很多单接口的前置数据处理又是一致的,比如:

  ["input"]["title"] = "autoTest" + str(time.time())
          createCommodityParams["input"]["mallCode"] = self.mallCode
          createCommodityParams["input"]["skuList"][0]["price"] = random.randint(1,10)
          createCategoryParams["input"]["categoryName"] = "autoTestCategory" + str(time.time())
          createCouponParams。。。
          createPublicityParams。。。
          publishCommodityParams。。。
          publishPublicityParams。。。

  重新封装的话还要再处理这一步,就有点麻烦且不符合我们的复用性设计了,因此我们对service层再细化为3层,分别为:

  apiObject:

  单接口的预处理层,这一层主要作用是单接口入参的构造,接口的请求与响应值返回

  每个接口请求不依赖与业务步骤,都是单接口的请求;

  此外一些简单固定的入参构建也直接放在这里处理,比如随机的商品名,title等,和具体业务流程无关,针对所有调用此接口的场景均适用。

  caseService:

  多接口的预处理层,这一层主要是??测试步骤(teststep)??或场景的有序集合。

  用例所需要的步骤,通过每一个请求进行组合,每一个步骤都对应着一个API请求,这些步骤会组成一个个场景,各个场景之间可以互相调用组成新的场景,以适应不同的测试用例需求。

  场景封装好以后可以供不同的测试用例调用,除了当前项目的用例,其他业务线需要的话也可从此??caseService??中选择调用,提高复用性的同时也避免了用例相互依赖的问题。

  util:

  这一层主要放置针对当前业务的接口需要处理的数据。

  在实际编写测试步骤时,可能部分接口的参数是通过其他接口获取后经过处理才可以使用,或是修改数据格式,或是修改字段名称,亦或是某些 value 的加解密处理等。

  细化分层后,各层的职责便更加清晰明确,具体如下图:

1-7.png


作者:CeshirenTester    

来源:http://www.51testing.com/html/94/n-7792394.html

  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          • 读者提问:『阿常你好,作为测试,你可以讲讲测试人员的价值体现在哪里吗 ?』阿常回答:很多小伙伴对于这个问题有困扰,阿常来说说自己的观点,我觉得测试人员的价值主要体现在以下四个方面:1、给产品发布增添信心经过测试人员的测试验证,产品和研发才会相信本次产品发布是一次可靠的发布,没有经过测试验证而直接上生产,整个项目组成员都会惶恐不安。2、需求评审,帮产品梳理逻辑测试人员有时会比产品还要熟悉平台的整体业务逻辑,当产品提出一个新需求时,测试人员可以帮产品去梳理已有的业务逻辑,帮助产品判断新业务需求是否合理、跟已有业务逻辑是否有冲突。3、编写用例,帮开发梳理需求测试人员在研发提交测试之前就编写...
            0 0 1785
            分享
          • WEB测试和APP测试从流程上来说,没有区别。都需要经历测试计划方案,用例设计,测试执行,缺陷管理,测试报告等相关活动。从技术上来说,WEB测试和APP测试其测试类型也基本相似,都需要进行功能测试,性能测试,安全性测试,GUI测试等测试类型相同点:不管是传统行业的web测试,还是新兴的手机app测试,都离不开测试的基础知识:同样的设计测试用例方法:边界值分析法、等价类划分法、错误推测法、场景法等同样的测试方法:黑盒测试,验证业务功能是否正确符合用户或者设计预期;都要检查UR:界面的布局、风格和按钮等是否简洁美观、是否统一等;页面性能检测:测试页面载入和翻页的速度、登陆时长、内存是否溢出等;应用...
            13 14 2378
            分享
          •   测试用例编写流程:  · 需求分析  · 提取测试点  · 测试用例编写  · 测试用例评审  1.需求分析:  a、【业务需求】关注系统是否满足业务  b、【用户需求】关注系统是否满足用户习惯  c、【功能需求】关注系统是否满足功能需求  2.测试用例编写注意以下几点:  a、根据项目的实际情况设计测试用例表格  b、用例格式不是固定的,不要生搬硬套  c、根据具体的情况编写  一般测试用例包含的内容:  [ 测试用例包含的内容 ]  用例编号:唯一 --身份证号。  用例名称:用例的名字,要求言简意赅 --姓名。  测试背景:这条用例主要测试什么东西。  前置条件:执行这条措...
            0 0 925
            分享
          •   作为一名Tester,无论是面试还是工作,我们都常常会遇到该问题,毕竟现在大部分接手的项目都是中小型的项目,很多又是生疏行业的系统,所以这个问题就会常常伴随我们,那么遇到这个问题该怎么办呢,现在我们就分下面6点来讨论一下。  1.了解测试任务  我看网上有些博主一上来就让大家看资料了解系统,就是下面讲的第二点,当然这样做也行,但是会导致效率低下,就像我们上学时做阅读理解一样,最正确的做法应该是带着问题去看资料,所以我们应该一上来明确测试任务,然后带着这些测试任务的问题去看资料。  2.从现有资料中获取信息  明确测试任务后,就可以问研发团队要该项目的所有资料了,这里面主要包括产品需求文档(...
            0 0 1132
            分享
          •   51Testing软件测试网正在收集测试行业问卷结果,如果你也想为测试行业的前景助力,就点击下方的链接提交答案吧,还有精美礼品等你拿(测试课程五选二)。链接:http://vote.51testing.com/  项目背景  某项目是一个OA管理系统(外包给一家南方公司),以JAVA为开发语言、VUE为前端框架、MySQL为后端数据库管理系统。去年9月开始立项、开发,一直到今年6月中旬发布,减除项目暂停期间,共历经7个多月。  项目规模  该系统主要由六大模块组成。项目成员有1名项目经理、1名开发经理、10余位开发、2名测试。  项目测试情况  2021年11月份末,部门经理找到笔者,让笔...
            0 0 895
            分享
      • 51testing软件测试圈微信