效能度量 专栏文章 质量保障系统的落地实践 (四) 效能管理设计 - 造数工厂

亦攸 · 2024年05月27日 · 最后由 亦攸 回复于 2024年06月14日 · 7159 次阅读

往期文章

专栏文章 质量保障系统的落地实践 (一) 概览篇
专栏文章 质量保障系统的落地实践 (二) 项目管理设计 - 基础信息与缺陷信息设计
专栏文章 质量保障系统的落地实践 (二) 项目管理设计 - 代码信息设计
专栏文章 质量保障系统的落地实践 (三) CI 管理设计 - 基础设计
专栏文章 质量保障系统的落地实践 (三) CI 管理设计 - 集成设计

前言

书接上文, CI 管理设计 - 集成设计篇介绍了质量保障系统如何与自动化框架建立有效关联,本篇文章就在这个基础上做发散介绍。在实际测试过程中,往往有一定的造数需求—通过自动化脚本,创造出符合测试所需的数据。可见造数脚本也是需要使用自动化脚本编程的,但同时造数脚本又不同于自动化校验校验。一来造数脚本往往不需要校验逻辑,只需要执行创建数据即可;二来造数脚本往往需要具备根据外部传参来生成满足期望的数据,而不全是随机数据。将积累下来的造数脚本统一管理起来,就是接下来我们要谈谈的造数工厂。

造数脚本编写

由于造数脚本需要依据外部需求来改变生成的数据属性,那么该怎么处理?举一个具体的例子,比如场景上需要生成一个具备姓名、身份证、性别的用户,若是没有指定姓名、身份证、性别,则随机生成;若是外部指定姓名、身份证、性别,则使用外部的数据,那么伪代码的形式:

def DiyPerson(name=None, idcard=None, sex=None):
  if name is None:
    name = randomName()
  if idcard is None:
    idcard = randomIdCard()
  if sex is None:
    sex = randomSex()
  data = {
    "name": name,
    "sex": sex,
    "idcard": idcard
  }
  response = requests.post(url, json=data)

上述方式是比较常见的处理思路,所有变量均设置一个默认空值,若是没有传递,则随机生成数据。只是编写相对比较繁琐,特别是遇上表单项特别多的情况下,那么该怎么处理比较合适?大家注意到最后发起接口请求的时候,需要拼接data主体,里面包含了所有数据内容,是不是只要想办法把 data 的数据替换了就可以了:

def repalceRequestData(request_data, replace_data):
  data_ = {}
  for key, value in request_data.items():
    if key in replace_data:
      value = replace_data[key]
    data_[key] = value
  return data_

def DiyPerson(replace_data={}):
   name = randomName()
   idcard = randomIdCard()
   sex = randomSex()
   data = {
    "name": name,
    "sex": sex,
    "idcard": idcard
  }
  data_ = repalceRequestData(data, replace_data)
  response = requests.post(url, json=data_)

使用外部传递的 replace_data 属性,在接口调用前完成属性替换。那么可能有人要问,这么写的话,name、idcard、sex 属性的赋值动作重复了,不是会产生执行效率浪费吗?确实,这个方案会有一定执行效率的损耗,但是也有个明显的好处,就是改造成本很小。一般来说在设计自动化脚本的时候,为了脚本能够多次执行,很多数据往往采用随机生成的方案,如上述例子中的身份证、为避免身份证重复,所以代码中往往不会写死某一数据,所以自动化脚本的编写模板一般如下:

def DiyPerson():
   name = randomName()
   idcard = randomIdCard()
   sex = randomSex()
   data = {
    "name": name,
    "sex": sex,
    "idcard": idcard
  }
  response = requests.post(url, json=data)

大家可以对比一下传入 replace_data 的方案与自动化脚本编写的模板方案的差别,就可以很直观地看到使用 replace_data 的造数脚本方案只需要在自动化脚本的基础上完成少量改造即可,即:1、调用repalceRequestData方法;2、传入 replace_data。按照这样的方案编写造数脚本的效率将会大幅提升。

造数脚本触发

在 CI 管理的部分,我们提到了基于不同公司基建的处理方法,此处也是类似。若是公司有完整的执行平台,我们就可以借助这个平台完成造数脚本的触发;若是公司不具备条件,那么我们就通过命令行自行触发造数脚本。有兴趣的小伙伴可以翻看专栏文章 质量保障系统的落地实践 (三) CI 管理设计 - 集成设计

造数脚本反馈

谈完了造数脚本的触发,接下来很自然的就会想到触发后的结果如何反馈了。还是以上述的例子来讲解,我们通过脚本定制了一个名叫张三、性别为男的用户信息,那么这条数据是否生成,生成后用户的 ID 等信息如何告知调用者?这又是一个问题。
若是公司具备自动化执行平台,虽然可以解决调用的问题,但是同时会带来另一个问题,这类平台的执行结果反馈往往是通用模板,并不能完全满足造数需求的反馈:

若是公司不具备自动化执行平台,那么就更无从说起执行反馈的情况了。那么该怎么办?
解决方案就是我们自行补全这部分能力,我们编写一套脚本,待执行完成后,将反馈给质量保障平台。接下来还是以具体的例子来说明:
1、首先我们需要创建用户之后,自定义生成通知我们的消息体:

data = {
    "name": name,
    "sex": sex,
    "idcard": idcard
  }
  data_ = repalceRequestData(data, replace_data)
  response = requests.post(url, json=data_)
  try:
    response = response.json()
    userId = response["data"]["id"]
    msg = f"创建用户成功,传参:{data_},用户id:{userId}."
    success = true
  except json.JsonDecodeError:
    msg = f"创建用户失败,传参:{data_}."
    success = false
   except KeyError:
    msg = f"创建用户失败,传参:{data_},接口响应:{response}."
    success = false

  # 至此我们可以标记出此次执行是否成功,以及成功或失败的具体信息,将信息存储到文件中
  with open(result.json, "w") as f:
    item = {
      "success": success,
      "msg": msg
  }
    f.write(json.dumps(item))

2、其次已经将消息存储在了 result.json 文件中,那么接下来只需要解析这个文件,想办法把这个文件的 json 内容回调给质量保障平台即可。若是有执行平台,这类平台往往使用 jenkins 等集成方案,允许加入执行脚本,那么只要将解析 result.json 文件,调用质量保障平台的接口的脚本嵌入就能完成反馈回调;若是没有执行平台,那么就更方便处理了,举个例子,如果执行脚本的命令为:python3 userFlow.py,那么我们只需要在命令后拼接上执行回调函数的命令即可:python3 userFlow.py;python3 callback.py,由于命令行是顺序执行的,所以命令:python3 userFlow.py;python3 callback.py将保证完成造数脚本执行,反馈信息写入 result.json 文件后,再执行 callback.py 的脚本,这样我们就可以在这个 callback.py 文件中处理读取 json 文件,回调质量保障平台的逻辑:

# callback.py
with open(result.json,) as f:
   content = json.loads(f.read())
   response = requests.post(url, json=content)

3、最后质量保障平台处理回调数据:

msg = data["msg"]
success = data["success"]
if success:
  notify_msg = f"造数执行成功,执行信息:{msg}."
else:
  notify_msg = f"造数执行失败,执行信息:{msg}."

# 通知调用方
dingTalkNotify(webhook, notify_msg)

人效统计

既然完成了整个造数工厂的搭建,就要考虑数据沉淀的问题了,毕竟没有数据支撑,价值很难体现。既然打通了整个造数逻辑,那么我们只需要在每个造数脚本上增加预估节约的造数时间成本,如 5 分钟、7 分钟的配置。在触发造数脚本之前,先保存一条造数执行日志记录,将状态置为进行中。当造数脚本完成回调质量保障平台时,将这条记录置为完成,统计时将所有完成状态的执行日志进行汇总,统计节约的时长,就可以得出节约人效。

# 效能管理-造数脚本配置
class DataFactoryConfigInfo(BaseModel):
    department_id = models.IntegerField(verbose_name=u"归属组织节点")
    name = models.CharField(max_length=150, verbose_name=u"造数脚本名称")
    per_period = models.IntegerField(default=0, verbose_name=u"单次节约时间(分)")
    owner_name = models.CharField(max_length=11, verbose_name=u"负责人姓名")
    owner_phone = models.CharField(max_length=11, verbose_name=u"负责人手机号")

    class Meta:
        db_table = "Data_Factory_Config_Info"
        verbose_name = "效能管理-造数脚本配置"
        verbose_name_plural = verbose_name

# 效能管理-造数脚本执行日志
class DataFactoryLogInfo(BaseModel):
    department_id = models.IntegerField(verbose_name=u"归属组织节点")
    config_id = models.IntegerField(verbose_name=u"造数脚本配置id")
    name = models.CharField(max_length=150, verbose_name=u"造数脚本名称")
    period = models.IntegerField(default=0, verbose_name=u"节约时间(分)")
    owner_name = models.CharField(max_length=11, verbose_name=u"负责人姓名")
    owner_phone = models.CharField(max_length=11, verbose_name=u"负责人手机号")
    env = models.CharField(max_length=20, verbose_name=u"执行环境")
    is_done = models.BooleanField(default=False, verbose_name=u"是否执行完成")
    caller_name = models.CharField(null=True, blank=True, max_length=11, verbose_name=u"调用者姓名")
    caller_phone = models.CharField(null=True, blank=True, max_length=11, verbose_name=u"调用者手机号")
    response = models.TextField(null=True, blank=True, verbose_name=u"造数调用结果")

    class Meta:
        db_table = "Data_Factory_Log_Info"
        verbose_name = "造数脚本执行日志"
        verbose_name_plural = verbose_name

总结

本篇文章基于 CI 管理部分进行的拓展介绍。若是能完全理解这些设计思路,那么我们测试人员搭建质量保障平台的能力将会得到一定的提升,可以不那么依赖现成的基建能力,更不会受制于基建能力,希望能够给大家一些帮助,谢谢。

共收到 15 条回复 时间 点赞

欢迎讨论

这里,我问一下,针对那个替换的部分,是否使用字典的形参会好一点,这样直接取值而不用去替换一次,效率是否更快一些(一个小白,代码学习没多久,大佬看到请别喷)

替换方案确实很多,之所以采用这种方案,是考虑到如何从已经编写好的自动化脚本中快速形成造数脚本。按照本篇文章的方案,编写造数脚本,可直接将已经成熟的自动化脚本整体拷贝,移除非必要校验逻辑,增加一行替换代码就可以了,成本比较低。

所以这里的效率更多考虑的不是代码执行效率,而是人工改动的效率。

需要替换的数据全是有逻辑的,有什么好的建议吗?

测试菜鸟 回复

一般来说,在自动化脚本已经编写的基础上,只需要关注替换的值就可以了,比如 A 字段是时间戳,在自动化脚本里要做时间戳的格式转换,加减计算等操作,最后得到一个处理后的 A‘字段,那么 replaceData 里只需要传入你需要的 A’ 字段即可,无需再进行额外的处理逻辑;若是真的需要,那只能额外加一些定制函数进行处理了。

亦攸 回复

大佬这个是针对你们公司的业务定制的么,还是一套通用的,如果可以的话,能和您学习学习么

需求确实是由公司业务产生的,不过实现的思路和方案是通用的。

亦攸 #10 · 2024年06月07日 Author

当然可以互相交流

仅楼主可见
亦攸 #12 · 2024年06月12日 Author

私信吧

亦攸 #13 · 2024年06月13日 Author

你的联系方式可以私信或者评论给我,用仅楼主可见

仅楼主可见

大佬想问下有开源吗,想学习一下

亦攸 #17 · 2024年06月14日 Author
Ninja 回复

涉及到产出归属问题,现阶段不能开源

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册