專欄文章 質量保障系統的落地實踐 (四) 效能管理設計 - 造數工廠

亦攸發表於2024-05-27

往期文章

專欄文章 質量保障系統的落地實踐 (一) 概覽篇
專欄文章 質量保障系統的落地實踐 (二) 專案管理設計 - 基礎資訊與缺陷資訊設計
專欄文章 質量保障系統的落地實踐 (二) 專案管理設計 - 程式碼資訊設計
專欄文章 質量保障系統的落地實踐 (三) 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 管理部分進行的擴充介紹。若是能完全理解這些設計思路,那麼我們測試人員搭建質量保障平臺的能力將會得到一定的提升,可以不那麼依賴現成的基建能力,更不會受制於基建能力,希望能夠給大家一些幫助,謝謝。

相關文章