快速API自動化測試

  • 2019 年 11 月 30 日
  • 筆記

我們平時寫API,時效性太慢了。而且花費的成本代價太高。特別是有嚴重的滯後性。當平台多,業務多,迭代多的時候,介面自動化實現出來的時候,黃花菜都涼了。

有沒有一個方式能夠快速測試API呢?

最近實踐了一下httprunner, 可以作為我們的API自動化測試的一個補充,高低搭配。

HttpRunner 是一個基於 Python 開發的測試框架,可以運行在 macOS、Linux、Windows 系統平台上。

它的原理也很簡單 總體的思想就是用代理工具錄製,然後生成我們常見的json格式,通過設置變數,替換一些常量,加上一些驗證點,批量發送請求,生成測試報告,從而達到測試介面的目的。

安裝:

pip install httprunnerorpip install -U HttpRunner

錄製:

用charles錄製,保存成har文件格式。

運行:

生成用例har2case Documents/cae1/UAT_Cool.harhar2case Documents/cae1/UAT_Cool.har -2y  運行用例hrun Documents/cae1/UAT_Cool.jsonhrun Documents/cae1/UAT_Cool.yml

image.png

然後就可以在report中看測試報告了。

以上是一個很簡單的過程,一般對於正規的測試框架來說,我們需要繼續以下一些步驟來整理我們的數據。

整理

生成測試用例 參數關聯 變數聲明與應用 抽取公共變數 參數化數據 優化測試結果

對於有些變數,需要上下文的,這個框架可以用extract來獲取,然後用變數替換

這個過程如果用手工的話,比較麻煩,可以寫個腳本來自動實現

import reimport json    json_file = "/Users/anderson/work/api/case1/UAT_Cool.json"    def rewrite_file():    with open(json_file, 'r') as load_f:        load_dict = json.load(load_f)          load_dict["config"]["base_url"] = "http://m.cn"        load_dict["config"]["verify"] = False        value = {"userName": "t74951", "password": "111111"}        (load_dict["config"]["variables"]).update(value)          if "name" in load_dict["teststeps"][0]:            load_dict["teststeps"][0]["extract"] = [                {"token": "content.serviceResponse.token", "sessionId": "content.serviceResponse.sessionId"}]            if "userName" and "password" in load_dict["teststeps"][0]["request"]["json"][            "serviceRequest"]:            load_dict["teststeps"][0]["request"]["json"]["serviceRequest"]["userName"] = "$userName"            load_dict["teststeps"][0]["request"]["json"]["serviceRequest"]["password"] = "$password"      for i in range(len(load_dict["teststeps"])):        if "url" in load_dict["teststeps"][i]["request"]:            load_dict["teststeps"][i]["request"]["url"] = re.sub("[a-zA-z]+://.*.(com|cn)", "",                                                                 load_dict["teststeps"][i]["request"]["url"])      str = json.dumps(load_dict)    obj = re.compile(r'"sessionId": "(w+)"')    ret = obj.findall(str)    for i in ret:        str = str.replace(i, "$sessionId")      obj = re.compile(r'"token": "(w+)"')    ret = obj.findall(str)    for i in ret:        str = str.replace(i, "$token")      str = json.loads(str)      with open(json_file, "w") as dump_f:        json.dump(str, dump_f, indent=4)    rewrite_file()

增加checkpoint:

現在還有一個問題,就是checkpoint太少了,只是檢測了狀態是否200,如果手動增加,則太慢了。有一個辦法就是自動增加。可以寫yaml文件,將需要檢測的部分,都放到文件裡面。例如:

oneapp:  coursestructure:    api: /services/api/mobile/service/coursestructure    eq:       - ["content.serviceResponse.level.levelCode", "0A"]
import jsonimport osimport reimport shutil  har_dir = '/Users/anderson/Documents/case1'json_dir = '/Users/anderson/Documents/case1'  import json  import yaml    class YAML():    # Write YAML file    def write_yml(self, save_path, data):        with open(save_path, 'w', encoding='utf8') as outfile:            try:                yaml.safe_dump(data, outfile, default_flow_style=False, allow_unicode=True)            except yaml.YAMLError as exc:                print(exc)                  # Read YAML file      def read_yml(self, load_path):        with open(load_path, 'r') as stream:            try:                data_loaded = yaml.safe_load(stream)            except yaml.YAMLError as exc:                print(exc)        return data_loaded    def add_checkpoint(target_file):    file_path = "/Users/anderson/Documents/api.yml"    yaml_file = YAML().read_yml(file_path)["oneapp"]      json_raw = open(target_file, "r")      json_file=json.loads(json_raw.read())    print(json_file)    name_list = []    for i, ele in enumerate(json_file["teststeps"]):        name_list.append(ele["name"])      for key in yaml_file.keys():        if yaml_file[key]["api"] in name_list:            index = name_list.index(yaml_file[key]["api"])              if len(yaml_file[key]["eq"]):                for checks in yaml_file[key]["eq"]:                    (json_file["teststeps"][index]["validate"]).append({"eq": checks})      # json_file = json.dumps(json_file, indent=4)    with open(target_file, "w") as dump_f:        json.dump(json_file, dump_f, indent=4)      print(json_file)    json_raw.close()    def run_case(path):    run_cmd = "hrun {} --failfast --log-level info".format(path)    os.system(run_cmd)    # rewrite_file()  if __name__ == "__main__":      #check_folder(json_dir)    extract_har(har_dir)    source_json = [x for x in os.listdir(har_dir) if x.endswith('json')]    if len(source_json):        for source in source_json:            rewrite_file(os.path.join(har_dir, source), os.path.join(json_dir, source))      target= os.path.join(json_dir, source_json[0])    print(target)    add_checkpoint(target)      if is_json_exist:        json_file = [x for x in os.listdir(json_dir) if x.endswith('json')]          for source in json_file:            run_case(os.path.join(json_dir, source))

我們可以寫個腳本,自動增加需要測試的點,效率增加很多。

這樣,生成的report裡面也可以看到這個checkpoint點了。

管理case:

工具用了一個命令來管理case. 按照這種格式,就很容易管理case了。

如果有多個環境的話,再增加一點程式碼,用來數據管理和環境管理,可以結合jenkins一起使用。如果介面有變的話,重新錄製一套也不需要花多少時間,這樣的話,就能快速迭代了。