1. 程式人生 > >apiAutoTest:支援自定義函式,用例中可呼叫

apiAutoTest:支援自定義函式,用例中可呼叫

# 0. 前言 apiAutoTest從去年8月以來開源至今,也更新了不少內容,一起來看看吧 - 第一個版本 ``` - 2020/08/08 增加實際響應儲存資料的方法,並在字典可以處理依賴見tools/svae_response.py - 2020/08/09 實現多檔案上傳,介面中Path引數依賴處理 初步實現用迭代的方式來處理介面中的資料依賴關係 ``` - 第二個版本 ``` - 2020/11/18 使用re庫替換之前的字典迭代方式來處理資料依賴 - 2020/11/21 config.yaml檔案中新增基準header設定 - 2020/11/22 支援預期結果中欄位斷言時使用語法糖來實現動態欄位斷言 - 2020/12/08 優化斷言資訊,增加資料庫(支援mysql)查詢操作, 使用`@pytest.fixture(scope="session")`來託管資料庫物件,用例新增sql欄 - 2020/12/16 使用conftest.py 初始化用例, 增加失敗重跑機制, 增加執行檔案run,優化test_api.py冗餘程式碼 ``` - 第三個版本 ``` - 2021/01/19 新增資料清洗功能(測試開始前進行資料庫備份-分別在伺服器和本地進行,測試結束後將備份用以恢復資料-將嘗試從伺服器和本地恢復到伺服器資料庫中,docker部署的mysql服務已本地除錯通過,直接linux部署的mysql並未測試) - 2021/02/27 新增hooks.py檔案(可在此處自定義方法,並用於用例當中,注意請務必在定義的方法中使用return),移除上次更新的eval語法糖,增加用例處理前的日誌 ``` 一度說不會再更新維護程式碼,結果還是慢慢的更新了... # 1. 自定義函式實現的故事 > 這是今天更新的,主要需求來自一個apiAutoTest的學習者反饋,這裡感謝他,在此之前另一個小夥伴說他需要用上個介面返回的id欄位進行運算, 很多測試框架都有這個功能,但我給apiAutoTest的定位是個工具,也就造個輪子嘛 ![](https://gitee.com/zy7y/blog_images/raw/master/img/20210227154756.png) # 2. 用例中如何使用自定義函式 ## 2.1 在tools/hooks.py中定義好函式 ```python def get_current_highest(): """獲取當前時間戳""" return int(time.time()) def sum_data(a, b): """計算函式""" return a + b ``` ## 2.2 在用例中如何使用該函式 > 語法糖: @函式名()@: 使用無引數函式 > > @函式名(引數1, 引數2)@: 向函式傳遞引數 > > ps: **函式引數相容apiAutoTest中的提取依賴語法`&此處為jsonpath語法&`** ### 用例(怕截圖不清所以就這裡簡易模擬了兩條) |用例編號|用例標題|介面路徑|是否執行|token操作|請求方式|入參關鍵字|上傳檔案|請求資料|後置sql|預期結果| | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | | case_001 | post請求實現登入 | login | 是 | 寫 | post | data | | {"username": "admin", "password": "123456"} | select * from user where id=&$.case_002.data.id&; | {"$.meta":{ "msg": "登入成功", "status": 200 }} | | case_002 | 除錯函式sum_data(),從path需要運算 | users/@sum_data(&$.case_001.data.id&, 2)@/ | 是 | 讀 | put | data | | {"username": "tery","password": @sum_data(&$.case_001.data.id&, 66)@, "timer": @get_current_highest()@, "timer_str": " @get_current_highest()@"} | | {"$.meta":{"msg": "設定狀態成功", "status": 200}} | ### 執行日誌(執行上述用例得到日誌如下) ```log 2021-02-27 16:06:50.538 | DEBUG | api.base_requests:send_request:34 - 用例進行處理前資料: 介面路徑: login 請求引數: {"username": "admin", "password": "123456"} 後置sql: select * from user where id=&$.case_002.data.id&; 預期結果: {"$.meta":{ "msg": "登入成功", "status": 200 }} 2021-02-27 16:06:50.765 | INFO | api.base_requests:send_api:81 - 最終請求地址:http://www.ysqorz.top:8888/api/private/v1/login 請求方法:post 請求頭:{'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-CN,zh;q=0.9', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'} 請求引數:{'username': 'admin', 'password': '123456'} 上傳檔案:None 響應資料:{'data': {'id': 500, 'rid': 0, 'username': 'admin', 'mobile': '12345678', 'email': '[email protected]', 'token': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjUwMCwicmlkIjowLCJpYXQiOjE2MTQ0MTMyMTAsImV4cCI6MTYxNDQ5OTYxMH0.cZTYLARKNj8SKlPGPdIUh9RmyQaYAJnJrLObaKiNiU4'}, 'meta': {'msg': '登入成功', 'status': 200}} 2021-02-27 16:06:50.773 | INFO | tools.data_process:save_response:27 - 新增key: case_001, 對應value: {'data': {'id': 500, 'rid': 0, 'username': 'admin', 'mobile': '12345678', 'email': '[email protected]', 'token': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjUwMCwicmlkIjowLCJpYXQiOjE2MTQ0MTMyMTAsImV4cCI6MTYxNDQ5OTYxMH0.cZTYLARKNj8SKlPGPdIUh9RmyQaYAJnJrLObaKiNiU4'}, 'meta': {'msg': '登入成功', 'status': 200}} 2021-02-27 16:06:50.775 | INFO | tools.data_process:assert_result:115 - 第1個斷言,實際結果:{'msg': '登入成功', 'status': 200} | 預期結果:{'msg': '登入成功', 'status': 200} 斷言結果 True 2021-02-27 16:06:50.775 | DEBUG | api.base_requests:send_request:34 - 用例進行處理前資料: 介面路徑: users/@sum_data(&$.case_001.data.id&, 2)@/ 請求引數: {"username": "tery","password": @sum_data(&$.case_001.data.id&, 66)@, "timer": @get_current_highest()@, "timer_str": " @get_current_highest()@"} 後置sql: 預期結果: {"$.meta":{"msg": "設定狀態成功", "status": 200}} 2021-02-27 16:06:50.775 | DEBUG | tools:rep_expr:45 - &$.case_001.data.id& 替換的值為 500 2021-02-27 16:06:50.775 | DEBUG | tools:rep_expr:50 - 執行hooks函式sum_data(500, 2) 替換的值為 502 2021-02-27 16:06:50.775 | DEBUG | tools:rep_expr:45 - &$.case_001.data.id& 替換的值為 500 2021-02-27 16:06:50.783 | DEBUG | tools:rep_expr:50 - 執行hooks函式sum_data(500, 66) 替換的值為 566 2021-02-27 16:06:50.783 | DEBUG | tools:rep_expr:50 - 執行hooks函式get_current_highest() 替換的值為 1614413210 2021-02-27 16:06:50.783 | DEBUG | tools:rep_expr:50 - 執行hooks函式get_current_highest() 替換的值為 1614413210 2021-02-27 16:06:50.835 | INFO | api.base_requests:send_api:81 - 最終請求地址:http://www.ysqorz.top:8888/api/private/v1/users/502/ 請求方法:put 請求頭:{'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-CN,zh;q=0.9', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36', 'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjUwMCwicmlkIjowLCJpYXQiOjE2MTQ0MTMyMTAsImV4cCI6MTYxNDQ5OTYxMH0.cZTYLARKNj8SKlPGPdIUh9RmyQaYAJnJrLObaKiNiU4'} 請求引數:{'username': 'tery', 'password': 566, 'timer': 1614413210, 'timer_str': ' 1614413210'} 上傳檔案:None 響應資料:{'data': {'id': 502, 'username': 'linken', 'role_id': 34}, 'meta': {'msg': '更新成功', 'status': 200}} 2021-02-27 16:06:50.835 | INFO | tools.data_process:save_response:27 - 新增key: case_002, 對應value: {'data': {'id': 502, 'username': 'linken', 'role_id': 34}, 'meta': {'msg': '更新成功', 'status': 200}} 2021-02-27 16:06:50.835 | INFO | tools.data_process:assert_result:115 - 第1個斷言,實際結果:{'msg': '更新成功', 'status': 200} | 預期結果:{'msg': '設定狀態成功', 'status': 200} 斷言結果 False 2021-02-27 16:06:53.418 | SUCCESS | __main__:run:43 - 報告已生成 ``` ### 分析日誌 從上述日誌可以看出語法糖`@sum_data(&$.case_001.data.id&, 2)@`執行之後的結果為`502`, 其處理的順序則是先`&$.case_001.data.id&` 提取出來得到的值是500, 然後呼叫函式sum_data(500, 2),然後執行這個函式並把結果502 與`@sum_data(&$.case_001.data.id&, 2)@`進行替換. # 3. 自定義函式實現程式碼 >因為這裡用例讀取出來的內容是字串,我影響中反射應該能做到這一點,然後就去找了下資料,然後我又找到`getattr()`這個內建函式但是這個函式不能解決用例帶引數的函式問題,然後我把目光移到了`exec()`內建函式,該函式可以執行字串的Python程式碼,然而我又遇到了問題,該函式裡面執行的Python程式碼變數在其他函式中不能順利取出來用,最後我找到了資料 在函式內部使用locals()得到一個區域性變數字典,通過字典取值的方式 把exec中的變數 取出來 ### `tools/hooks.py` ``` #!/usr/bin/env python # _*_ coding: utf-8 _*_ """ @project: apiAutoTest @file: hooks.py @author: zy7y @time: 2021/2/27 @site: https://cnblogs.com/zy7y @github: https://github.com/zy7y @gitee: https://gitee.com/zy7y @desc: 擴充套件方法, 2021/02/27 關於exec執行python程式碼可查閱資料:https://python3-cookbook.readthedocs.io/zh_CN/latest/c09/p23_executing_code_with_local_side_effects.html """ import time def exec_func(func: str) -> str: """執行函式(exec可以執行Python程式碼) :params func 字元的形式呼叫函式 : return 返回的將是個str型別的結果 """ # 得到一個區域性的變數字典,來修正exec函式中的變數,在其他函式內部使用不到的問題 loc = locals() exec(f"result = {func}") return str(loc['result']) def get_current_highest(): """獲取當前時間戳""" return int(time.time()) def sum_data(a, b): """計算函式""" return a + b ``` # `tools/__init__.py` > 寫到這裡發現篇幅過長了,所以這裡就把改動的地方程式碼貼出來吧 ```python #!/usr/bin/env/python3 # -*- coding:utf-8 -*- """ @project: apiAutoTest @author: zy7y @file: __init__.py.py @ide: PyCharm @time: 2020/7/31 """ import json import re import allure from jsonpath import jsonpath from loguru import logger from tools.hooks import * ... 上方程式碼省略 def rep_expr(content: str, data: dict, expr: str = '&(.*?)&') -> str: """從請求引數的字串中,使用正則的方法找出合適的字串內容並進行替換 :param content: 原始的字串內容 :param data: 在該專案中一般為響應字典,從字典取值出來 :param expr: 查詢用的正則表示式 return content: 替換表示式後的字串 """ for ctt in re.findall(expr, content): content = content.replace(f'&{ctt}&', str(extractor(data, ctt))) logger.debug(f"&{ctt}& 替換的值為 {str(extractor(data, ctt))} ") # 增加自定義函式得的呼叫,函式寫在tools/hooks.py中 for func in re.findall('@(.*?)@', content): content = content.replace(f'@{func}@', exec_func(func)) logger.debug(f"執行hooks函式{func} 替換的值為 {exec_func(func)}") return content ... 下方程式碼省略 ``` # 4. 原始碼地址 github: https://www.github.com/zy7y/apiAutoTest gitee: https://www.gitee.com/zy7y/apiAutoTest **其中最早版本(採用字典迭代方式處理依賴)在 version1.0分支** # 5. 致謝 > 感謝所有給予我幫助的人,文章,正在學習或使用apiAutoTest的同學們,其實個人開源這個專案以來個人有得到成就感,非常感謝 參考資料: [python3-cookbook](https://python3-cookbook.readthedocs.io/zh_CN/latest/c09/p23_executing_code_with_local_side_effects.html) # 6. 往日文章 [apiAutoTest: 開源啦](https://www.cnblogs.com/zy7y/p/13426816.html) [apiAutoTest: 使用re庫來處理介面之前的資料依賴](https://www.cnblogs.com/zy7y/p/14022398.html) [apiAutoTest: 增加資料隔離(測試前後備份/還原資料庫)](https://www.cnblogs.com/zy7y/p/14299472.html) [apiAutoTest: 增加自定義函式,用例中可以呼叫](https://www.cnblogs.com/zy7y/p/1445620