1. 程式人生 > >ApiTesting全鏈路自動化測試框架 - 初版釋出(一)

ApiTesting全鏈路自動化測試框架 - 初版釋出(一)

簡介

此框架是基於Python+Pytest+Requests+Allure+Yaml+Json實現全鏈路介面自動化測試。

主要流程:解析介面資料包 ->生成介面基礎配置(yml) ->生成測試用例(yaml+json) ->生成測試指令碼(.py) ->執行測試(pytest) ->生成測試報告(allure)

測試流程:初始化請求 ->處理介面基礎資訊 ->讀取前置介面用例 ->傳送前置介面 ->處理當前介面資料 ->傳送當前介面  ->檢查介面返回

介面自動化測試無非分幾大塊:測試用例設計、測試指令碼編寫、測試結果校驗、測試報告生成、測試配置管理。

其中常見有幾大難點:介面之間依賴關聯、測試資料與指令碼分離、測試資料引數化處理、全量自動化耗時。

而這些本框架通通已為你解決,你無須編寫任何程式碼,只需要你抓取介面資料包即可。

關於介面依賴:你只要填寫前置介面相對路徑即可,如果存在資料依賴關係,此時你也僅需要填寫前置介面對應的引數值,本框架將自動為你呼叫和替換關聯資料。

關於測試資料:本框架採用yaml記錄介面基本資訊,當請求引數和結果較大時,將單獨儲存到json檔案中,解決各類資料的錯綜複雜問題。

關於引數化:本框架採用常用工具使用的變數標識 ${var} ,通過正則表示式,自動檢索變數,自動為你替換變數,並且為你提供多種函式助手【$RandInt()、$GenGuid()】為你解決測試資料生成問題。

關於用例執行:本框架利用pytest擴充套件庫,支援多執行緒模式、失敗用例重試、用例模糊匹配等。

目前主要支援四種執行模式:

> 0 -不開啟自動生成測試用例功能,將直接執行測試

> 1 -根據手工編寫用例,自動生成測試指令碼,然後執行測試

> 2 -根據介面抓包資料,自動生成測試用例和測試指令碼,然後執行測試

> 3 -根據介面抓包資料,自動生成測試用例和測試指令碼,但不執行測試

注意:目前解析僅支援(.chlsj)格式,請使用Charles工具抓包匯出JSON Session File

目前支援多種函式助手(以下僅為示例,之後將單獨說明):

print('替換變數並計算表示式:', replace('$Eval(${unitCode}*1000+1)', {'unitCode': 9876543210}))
print('生成1-9之間的隨機數:', replace('$RandInt(1,9)'))
print('生成10位隨機字元:', replace('$RandStr(10)'))
print('從列表中隨機選擇:', replace('$RandChoice(a,b,c,d)'))
print('生成一個偽手機號:', replace('$GenPhone()'))
print('生成一個guid:', replace('$GenGuid()'))
print('生成一個偽微信ID:', replace('$GenWxid()'))
print('生成一個偽身份證:', replace('$GenNoid()'))
print('生成一個18歲偽身份證:', replace("$GenNoid(y-18)"))
print('生成下個月今天的日期:', replace("$GenDate(m+1)"))
print('生成昨天此時的時間:', replace("$GenDatetime(d-1)"))
替換變數並計算表示式: 9876543210
生成1-9之間的隨機數: 9
生成10位隨機字元: CB8512d4E6
從列表中隨機選擇: d
生成一個偽手機號: 18890688629
生成一個guid: 78A6698C-6793-11EB-8221-005056C00008
生成一個偽微信ID: AUTO9K6MRzVGfsNB4ZkIuSdXravD
生成一個偽身份證: 999577202102052043
生成一個18歲偽身份證: 953700200302056259
生成下個月今天的日期: 2021-03-05
生成昨天此時的時間: 2021-02-04 17:21:04.696745

 


框架流程圖

 


專案結構

 


執行入口(startup.py)

# -*- coding:utf-8 -*-
# @Time    : 2021/2/1
# @Author  : Leo Zhang
# @File    : startup.py
# ***********************
import os
import sys
import pytest
import logging


if __name__ == '__main__':
    from comm.script import writeLogs, writeCase
    from config import *

    # 開啟日誌記錄(預設logs目錄)
    writeLogs.MyLogs(ROOT_DIR+'logs')

    # 判斷執行模式
    if RC['auto_switch'] == 3:
        logging.info("根據介面抓包資料,自動生成測試用例和測試指令碼,但不執行測試!")
        writeCase.write_case(DATA_DIR, auto_yaml=True)
        sys.exit(0)

    elif RC['auto_switch'] == 2:
        logging.info("根據介面抓包資料,自動生成測試用例和測試指令碼,然後執行測試!")
        writeCase.write_case(DATA_DIR, auto_yaml=True)

    elif RC['auto_switch'] == 1:
        # 如果掃描路徑為空在則取專案page目錄
        if not os.path.exists(RC['scan_dir']):
            RC['scan_dir'] = PAGE_DIR
        logging.info("根據手工編寫用例,自動生成測試指令碼,然後執行測試!")
        writeCase.write_case(RC['scan_dir'], auto_yaml=False)

    else:
        logging.info("不開啟自動生成測試用例功能,將直接執行測試!")

    # 定義執行引數
    args_list = ['-vs', TEST_DIR,
                 '-n', str(RC['process']),
                 '--reruns', str(RC['reruns']),
                 '--maxfail', str(RC['maxfail']),
                 '--alluredir', REPORT_DIR+'/xml',
                 '--clean-alluredir']
    # 判斷是否開啟用例匹配
    if RC['pattern']:
        args_list += ['-k ' + str(RC['pattern'])]
    test_result = pytest.main(args_list)

    # 生成allure報告
    cmd = 'allure generate --clean %s -o %s ' % (REPORT_DIR+'/xml', REPORT_DIR+'/html')
    os.system(cmd)

執行配置(runConfig.yml)

# 執行專案名
project_name: PyDemo

# 執行模式:
auto_switch: 2
# 0 -不開啟自動生成測試用例功能,將直接執行測試
# 1 -根據手工編寫用例,自動生成測試指令碼,然後執行測試
# 2 -根據介面抓包資料,自動生成測試用例和測試指令碼,然後執行測試
# 3 -根據介面抓包資料,自動生成測試用例和測試指令碼,但不執行測試
# 注意:目前解析僅支援(.chlsj)格式,請使用Charles工具抓包匯出JSON Session File

# 掃描測試用例目錄(且僅當auto_switch=1時有用)
scan_dir:

# 使用模糊匹配測試用例(空則匹配所有)
pattern:

# 執行併發執行緒數(0表示不開啟)
process: 0

# 失敗重試次數(0表示不重試)
reruns: 0

# 本輪測試最大允許失敗數(超出則立即結束測試)
maxfail: 20

# 介面呼叫間隔時間(s)
interval: 1

# 測試結果校驗方式說明(共5種方式):
# no_check:不做任何校驗
# check_code:僅校驗介面返回碼code
# check_json:校驗介面返回碼code,並進行json格式比較返回結果(預設方式)
# entirely_check:校驗介面返回碼code,並進行完整比較返回結果
# regular_check:校驗介面返回碼code,並進行正則匹配返回結果

測試指令碼基礎模板(test_template.py)

# -*- coding:utf-8 -*-
# @Time    : 2021/2/2
# @Author  : Leo Zhang
# @File    : test_template.py
# ****************************
import os
import allure
import pytest
from comm.utils.readYaml import read_yaml_data
from comm.unit.initializePremise import init_premise
from comm.unit.apiSend import send_request
from comm.unit.checkResult import check_result
case_yaml = os.path.realpath(__file__).replace('testcase', 'page').replace('py', 'yaml')
case_path = os.path.dirname(case_yaml)
case_dict = read_yaml_data(case_yaml)


@allure.feature(case_dict["test_info"]["title"])
class TestTemplate:

    @pytest.mark.parametrize("case_data", case_dict["test_case"])
    @allure.story("test_template")
    def test_template(self, case_data):
        # 初始化請求:執行前置介面+替換關聯變數
        test_info, case_data = init_premise(case_dict["test_info"], case_data, case_path)
        # 傳送當前介面
        code, data = send_request(test_info, case_data)
        # 校驗介面返回
        check_result(case_data, code, data)

介面配置示例(apiConfig.yml) 

PyDemo:
  host: 10.88.88.141:20037
  headers:
    Content-Type: application/x-www-form-urlencoded;charset=UTF-8
  cookies:
  headtoken: xu5YwIZFkVGczMn0H0rot2ps7zRIbvrTHNwMXx1sJXg=

測試用例示例(findParam.yaml)

test_info:
  title: register
  host: ${host}
  scheme: http
  method: POST
  address: /api/register/findParam
  mime_type: application/x-www-form-urlencoded
  headers: ${headers}
  timeout: 10
  file: false
  cookies: false
  premise: false
test_case:
- summary: findParam
  describe: test_findParam
  parameter:
    params:
      unitCode: '3202112002'
      first: 0
      pym: ''
      pageSize: 10
      page: 0
    headtoken: ${headtoken}
  check:
    check_type: check_json
    expected_code: 200
    expected_result:
      success: true
      code:
      msg: 返回成功
      data:
      - '1'
      - '1'
      callTime:

測試報告示例(allure)

 


實戰演示

1、首先環境準備:Python  + Allure (這裡不做詳細說明,請參考我Pytest分類博文)

接著下載專案:https://github.com/Leozhanggg/ApiTesting (方便的話給個星,不要白嫖呀,哈哈。。。)

然後載入依賴:pip install -r requirements.txt   (或者使用Pycharm開啟,會自動彈出提示安裝)

 

2、使用Charles工具抓取介面資料包,並且匯出選擇JSON Session File (.chlsj) 格式 (工具自己百度下載吧)

 

3、新建一個專案MyTest目錄和一個data目錄,把抓取的介面資料包放置進來,然後修改runConfig.yml專案名為MyTest

 

4、直接開始執行,然後你就會發現專案目錄多了很多檔案,測試已經完成。。。沒錯,就是這麼簡單,你還可以檢視allure報告。

 

 


談談我自己

以往我使用過多種基於Python的自動化測試框架,特別是robotframework,簡單易上手,對於培養普通測試工程師比較迅速,但是優點同時也是缺點,由於RF自身侷限性,會讓簡單的語法變得複雜化,

如果你不做分層處理,可能會出現一條簡單的測試用例編需要寫上百行,後期維護更是非常麻煩,

我記得有一次檢查測試工程師的自動化測試用例時,發現竟然有兩百多行,對於RF這種表格語法兩百多行你知道閱讀是多麼的痛苦嘛。。。

當然這也是源於我們的專案性質,由於大資料業務,介面只是一小部分,而資料的校驗才是大頭,

並且涉及到多類資料庫,比如redis、mysql、es、hbase、solr等,而且有的介面會同時儲存到多個表然後同步到多個數據庫,校驗點數不過來。。。

就這樣前前後後我帶領著幾個測試工程師改了幾版,雖然最後大大的減少了測試程式碼,但是依然還是很多,

並且執行時長很難解決。所以從去年開始使用pytest測試框架,當然這也是我首次接觸pytest,第一個專案也改了幾版,但是由於純pytest編寫,

所有的東西都在一塊,改起來也比較簡單,最終的效果當然是質的提升,首先時程式碼方面可以輕鬆的做分層處理,不會受到RF之類的框架限制,

而在執行時長方面可以採用pytest自身的多執行緒模組,大大減少執行時長,同時大大提高了框架的擴充套件性。

 

而本框架源於https://github.com/wangxiaoxi3/API_service專案,加上自己實際專案實施經驗重構而來,保留了核心功能,增加了自己對介面自動化測試的理解。

特別對於關聯值處理方面,不在需要手動標記,而採用自動檢索方式,另外關於前置介面處理,也不在需要手動編寫,只需要指定前置介面相對路徑即可,並且多個用例可以巢狀。

另外在請求地址和訊息頭上,不在需要手動配置,將在介面資料解析中自動篩選訊息頭和請求地址,然後寫入介面公共配置中,除非有變動,否則無需做任何配置。

但是目前開發的第一版並沒有加入資料庫校驗,僅為了單純介面的自動化測試,後期將考慮加入資料庫校驗模組。以下為本人實際專案資料庫校驗示例:

 

※ 如果有任何疑問可以留言,當然如果覺得寫得不錯可以收藏、推薦一下,另外github幫忙給個星!!!

 

作者:Leozhanggg

出處:https://www.cnblogs.com/leozhanggg/p/14373878.html

原始碼:https://github.com/Leozhanggg/ApiTesting

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。