Python+Pytest+Allure+Jenkins 介面自動化框架
Python+Pytest+Allure+Jenkins 介面自動化框架
一、介面基礎
介面測試是對系統和元件之間的介面進行測試,主要是效驗資料的交換,傳遞和控制管理過程,以及相互邏輯依賴關係。其中介面協議分為 HTTP,RPC,Webservice,Dubbo,RESTful 等型別。
介面測試流程
1、需求評審,熟悉業務和需求
2、開發提供介面文件
3、編寫介面測試用例
4、用例評審
5、提測後開始測試
6、提交測試報告
兩種常見的 HTTP 請求方法:GET 和 POST
二、專案說明
本框架是一套基於 Python+Pytest+Requests+Allure+Jenkins 而設計的資料驅動介面自動化測試的框架。
技術棧
Python、Pytest、Requests、Excel、Json、Mysql、Allure、Logbook、Jenkins
三、介面測試框架結構圖
四、專案功能
Python+Pytest+Allure+Jenkins 介面自動化框架,實現 Excel 或 Json 維護測試用例,支援資料庫操作,利用封裝的請求基類調取相應的測試用例介面,獲取配置檔案中的環境地址與環境變數,結合 Pytest 進行單元測試,使用 LogBook 進行記錄日誌,並生成 allure 測試報告,最後進行 Jenkins 整合專案實現整合部署,併傳送測試報告郵件。
五、程式碼設計與功能說明
1、工具類封裝
1.1、log 日誌
目中的 log 日誌是 logbook 進行日誌記錄的,方便測試開發除錯時進行排錯糾正或修復最佳化。日誌可選擇是否列印在螢幕上即執行時是否在終端輸出列印。日誌格式輸出可調整。
handle_log.py 部分原始碼
def log_type(record, handler):
log = "[{date}] [{level}] [{filename}] [{func_name}] [{lineno}] {msg}".format(
date=record.time, # 日誌時間
level=record.level_name, # 日誌等級
filename=os.path.split(record.filename)[-1], # 檔名
func_name=record.func_name, # 函式名
lineno=record.lineno, # 行號
msg=record.message # 日誌內容
)
return log
# 日誌存放路徑
LOG_DIR = BasePath + '/log'
print(LOG_DIR)
if not os.path.exists(LOG_DIR):
os.makedirs(LOG_DIR)
# 日誌列印到螢幕
log_std = ColorizedStderrHandler(bubble=True)
log_std.formatter = log_type
# 日誌列印到檔案
log_file = TimedRotatingFileHandler(
os.path.join(LOG_DIR, '%s.log' % 'log'), date_format='%Y-%m-%d', bubble=True, encoding='utf-8')
log_file.formatter = log_type
# 指令碼日誌
run_log = Logger("global_log")
def init_logger():
logbook.set_datetime_format("local")
run_log.handlers = []
run_log.handlers.append(log_file)
run_log.handlers.append(log_std)
return ""
列印在終端的日誌,如下圖所示。
同時執行專案後,會在專案檔案 log 中自動生成一個以當天日期命名的 log 檔案。點選 log 日誌檔案可檢視日誌詳情即專案執行時所記錄的日誌或報錯日誌。如下圖所示。
1.2、配置檔案
專案中涉及到一些配置檔案如 username、password 或環境變數時,我們可透過配置檔案來獲取配置值。透過配置檔案中 key 與 value 的定義來確定獲取配置檔案的值。
handle_init.py 部分原始碼
class HandleInit:
# 讀取配置檔案
def load_ini(self):
file_path = BasePath + "/config/config.ini"
cf = configparser.ConfigParser()
cf.read(file_path, encoding='UTF-8')
return cf
# 獲取ini裡面對應key的value
def get_value(self, key, node=None):
if node == None:
node = 'Test'
cf = self.load_ini()
try:
data = cf.get(node, key)
logger.info('獲取配置檔案的值,node:{},key:{}, data:{}'.format(node, key, data))
except Exception:
logger.exception('沒有獲取到對應的值,node:{},key:{}'.format(node, key))
data = None
return data
獲取配置檔案中的值日誌如下圖所示。
1.3、Api 介面請求
獲取相關測試用例及介面用例配置,記錄請求相關引數的日誌,定義 Allure 測試報告的步驟。
handle_apirequest.py 部分程式碼
class ApiRequest:
def api_request(self, base_url, test_case_data, case_data):
get_name = None
get_url = None
get_method = None
get_headers = None
get_cookies = None
get_case_name = None
get_case_params = None
response_data = None
try:
get_name = test_case_data['config']['name']
get_url = base_url + test_case_data['config']['url']
get_method = test_case_data['config']['method']
get_headers = test_case_data['config']['headers']
get_cookies = test_case_data['config']['cookies']
except Exception as e:
logger.exception('獲取用例基本資訊失敗,{}'.format(e))
try:
get_case_name = case_data['name']
get_case_params = case_data['params']
except Exception as e:
logger.exception('獲取測試用例資訊失敗,{}'.format(e))
with allure.step("請求介面:%s,請求地址:%s,請求方法:%s,請求頭:%s,請求Cookies:%s" % (
get_name, get_url, get_method, get_headers, get_cookies)):
allure.attach("介面用例描述:", "{0}".format(get_case_name))
allure.attach("介面用例請求引數:", "{0}".format(get_case_params))
logger.info(
'請求介面名:%r,請求地址:%r,請求方法:%r,請求頭:%r,請求Cookies:%r' % (get_name, get_url, get_method, get_headers, get_cookies))
logger.info('請求介面名:%r,請求介面用例名:%r,介面用例請求引數:%r' % (get_name, get_case_name, get_case_params))
try:
response_data = baseRequest.run_main(get_method, get_url, get_case_params, get_headers)
except Exception as e:
logger.exception('用例請求返回失敗,{}'.format(e))
logger.info('請求介面名:%r,請求介面用例名:%r,返回引數:%r' % (get_name, get_case_name, response_data.json()))
return response_data
1.4、Excel 資料處理
1.4.1、Excel 測試用例
測試用例中維護在 Excel 檔案中,類中定義如何獲取 Excel 中的相關資料(如獲取某個單元格的內容,獲取單元格的行數,以及將資料寫入 Excel 中等操作)。
handle_exceldata.py 部分原始碼
class OperationExcel:
def __init__(self, file_name=None, sheet_id=None):
if file_name:
self.file_name = file_name
self.sheet_id = sheet_id
else:
self.file_name = ''
self.sheet_id = 0
self.data = self.get_data()
# 獲取sheets的內容
def get_data(self):
data = xlrd.open_workbook(self.file_name)
tables = data.sheets()[self.sheet_id]
return tables
# 獲取單元格的行數
def get_lines(self):
tables = self.data
return tables.nrows
# 獲取某一個單元格的內容
def get_cell_value(self, row, col):
return self.data.cell_value(row, col)
1.5、Json 資料處理
1.5.1、Json 測試用例
{
"config":{
"name":"post介面名",
"url":"/langdetect",
"method":"POST",
"headers":{
"Content-Type":"application/json"
},
"cookies":{
}
},
"testcase":[
{
"name":"測試用例1",
"params":{
"query":"測試"
},
"validate":[
{
"check":"status_code",
"comparator":"eq",
"expect":"200"
}
]
},
{
"name":"測試用例2",
"params":{
"query":"python"
},
"validate":[
{
"check":"msg",
"comparator":"eq",
"expect":"success"
}
]
}
]
}
1.5.2、Json 用例處理
獲取 Json 檔案中裡具體欄位的值。
handle.json.py 部分原始碼
class HandleJson:
# 讀取json檔案
def load_json(self, file_name):
if file_name == None:
file_path = ""
else:
file_path = file_name
try:
with open(file_path, encoding='UTF-8') as f:
data = json.load(f)
return data
except Exception:
print("未找到json檔案")
return {}
# 讀取json檔案裡具體的欄位值
def getJson_value(self, key, file_name):
if file_name == None:
return ""
jsonData = self.load_json(file_name)
if key == None:
getJsonValue = ""
else:
getJsonValue = jsonData.get(key)
return getJsonValue
2、基類封裝
2.1、請求基類封裝
介面支援 Get、Post 請求,呼叫 requests 請求來實現介面的呼叫與返回。介面引數包括,介面地址、介面請求引數、cookie 引數、header 引數。
class BaseRequest:
def send_get(self, url, data, header=None, cookie=None):
"""
Requests傳送Get請求
:param url:請求地址
:param data:Get請求引數
:param cookie:cookie引數
:param header:header引數
"""
response = requests.get(url=url, params=data, cookies=cookie, headers=header)
return response
def send_post(self, url, data, header=None, cookie=None):
"""
Requests傳送Post請求
:param url:請求地址
:param data:Post請求引數
:param data:Post請求引數
:param cookie:cookie引數
:param header:header引數
"""
response = requests.post(url=url, json=data, cookies=cookie, headers=header)
return response
# 主函式呼叫
def run_main(self, method, url, data, header, cookie=None):
try:
result = ''
if method.upper() == 'GET':
result = self.send_get(url, data, header, cookie)
elif method.upper() == 'POST':
result = self.send_post(url, data, header, cookie)
return result
except Exception as e:
logger.exception('請求主函式呼叫失敗:{}'.format(e))
3、介面測試用例編寫
3.1、介面測試用例
引用 Pytest 來進行介面的單元測試,透過 JSON 中多個測試用例來做為引數化資料驅動。結合 Allure 制定相應介面的測試報告。在介面返回斷言之前,我們先進行該介面的契約測試,我們採用的是 Pactverity 的全量契約校驗測試。當契約測試透過時,我們再進行返回引數的相關校驗測試。
test_getRequestJson.py 部分原始碼
@allure.feature('測試GET請求模組')
class TestRequestOne():
@allure.title('測試標題')
@allure.testcase('測試地址:https://www.imooc.com')
@user4ize('case_data', testCaseData['testcase'])
def test_requestOne(self, case_data):
try:
api_response = apiRequest.api_request(baseurl, testCaseData, case_data)
api_response_data = api_response.json()
# pactverity——全量契約校驗
config_contract_format = Like({
"msg": "成功",
"result": 0,
"data": EachLike({
"word": Like("testng")
})
})
mPactVerify = PactVerify(config_contract_format)
try:
mPactVerify.verify(api_response_data)
logger.info(
'verify_result:{},verify_info:{}'.format(mPactVerify.verify_result, mPactVerify.verify_info))
assert mPactVerify.verify_result == True
except Exception:
err_msg = '契約校驗錯誤'
logger.exception('測試用例契約校驗失敗,verify_result:{},verify_info:{}'.format(mPactVerify.verify_result,
mPactVerify.verify_info))
try:
for case_validate in case_data['validate']:
logger.info('斷言期望相關引數:check:{},comparator:{},expect:{}'.format(case_validate['check'],
case_validate['comparator'],
case_validate['expect']))
comparatorsTest.comparators_Assert(api_response, case_validate['check'],
case_validate['comparator'], case_validate['expect'])
logger.info('測試用例斷言成功')
except Exception as e:
logger.exception('測試用例斷言失敗')
except Exception as e:
logger.exception('測試用例請求失敗,原因:{}'.format(e))
3.2、主執行
運用 Pytest 和 Allure 的特性,命令列執行測試用例資料夾,並生成對應的 allure 測試報告。
if __name__ == "__main__":
pytest.main(['-s', '-v', 'test_case/testRequest/', '-q', '--alluredir', 'reports'])
4、Allure2 測試報告
當我們執行主函式時,並生成對應的測試用例報告時,我們可以看到在該資料夾中會生成對應的 json 檔案的測試報告。將 json 檔案的測試報告轉換成 html 形式的。命令如下
reports 是 json 格式測試報告存放的目錄位置,allure_reports 是 html 測試報告檔案生成的目錄位置。allure 命令如下。
allure generate reports -o allure_result/
專案根目錄下的 allure_reports 檔案,存放的是 allure 生成的測試報告。可看出檔案下有一個 HTML 檔案,可透過 Python 的編輯器 Pycharm 來開啟該 HTML 檔案(測試報告),或可透過 allure 命令來開啟該 HTML,展示 HTML 測試報告。如下所示。
測試報告檔案,HTML 測試報告如下。
allure 命令開啟 HTML 測試報告。命令如下所示。
allure open allure_result/
如下圖所示。
開啟生成的 HTML 測試報告如下圖所示。
5、Jenkins 整合
Allure+Jenkins 的分享,我之前在 Pytest+Allure+Jenkins 的部落格中已經分享過了。這塊可以出門左轉看看。前期的準備就不在這裡重複說明了。我們就直接來上手建立 Item 進行相關配置。
General 中 GitHub 專案地址的配置,將自己專案的 Git 複製至專案 URL 處。如下圖所示。
原始碼管理設定。勾選 Git,填寫相應的專案 Git 地址,Git 專案許可權所有者,以及對應的拉取程式碼的分支。如下圖所示。
配置構建命令。選擇 “執行 windows 批處理命令”,用 python 執行主函式執行指令碼,命令如下圖所示。
當我們在 Jenkins 裡面成功安裝 Allure 外掛後,直接可以在構建後操作中配置 Allure 的相關配置。在 Pytest+Allure+Jenkins 中已經說明過的。Results 應與專案執行時設定的 Allure 生成的 Json 格式報告的路徑一致,Report path 為 Allure html 報告結果生成檔案存放的路徑。
排除萬難之後,我們就可以用 Jenkins 來執行專案了。如下圖所示。
測試報告詳情頁,如下圖所示。
六、後期最佳化
1、介面測試用例資料依賴
2、測試報告郵件的傳送
七、感想
該框架是在涉及 python 的知識點比較多,將介面測試與契約測試結合起來。該框架是在工作之餘學習多篇文章,實戰上手逐步入門開始的,適合新手入門介面自動化實戰練習,僅供參考學習。框架中有不少可最佳化點與不足點,希望大家多多提建議或想法。
開源地址:https://github.com/wuwei88/Apiautomation.git
相關文章
- 介面自動化測試框架 HttpFPT框架HTTP
- 介面自動化(四):框架搭建(Python)框架Python
- 四.unittest介面自動化框架介紹框架
- Jmeter+Ant+Jenkins介面自動化框架JMeterJenkins框架
- 【python介面自動化】初識unittest框架Python框架
- 介面自動化實戰之框架搭建框架
- 介面自動化測試框架搭建的思路框架
- Jmeter+Ant+Jenkins介面自動化框架(續)JMeterJenkins框架
- 介面自動化測試框架搭建總結框架
- pytest+request+allure 介面自動化框架搭建分享框架
- <討論>2020年 的 python 介面自動化框架Python框架
- Python+Pytest+Allure+Git+Jenkins介面自動化框架PythonGitJenkins框架
- python 介面自動化Python
- 全自動化介面
- Httpclient 介面自動化HTTPclient
- 介面自動化與ui自動化區別UI
- Jmeter+Ant+Jenkins介面自動化測試框架搭建for WindowsJMeterJenkins框架Windows
- 介面自動化測試
- Python + requests + unittest + ddt 進行介面自動化測試的框架Python框架
- python介面自動化測試 —— unittest框架suite、runner詳細使用Python框架UI
- Java語言搭建介面自動化框架學習八(鑑權)Java框架
- 自動化測試框架框架
- titans Selenium 自動化框架框架
- 介面自動化之介面整理(抓包)
- Java語言搭建介面自動化框架學習一(單介面請求和響應)Java框架
- 一個基於多介面的業務自動化測試框架框架
- 關於介面測試——自動化框架的設計與實現框架
- jenkins+ant+jmeter介面自動化的持續整合測試框架JenkinsJMeter框架
- Python 介面自動化測試Python
- 『居善地』介面測試 — 9、介面自動化框架的傳送郵件實現框架
- JMeter 介面自動化測試(手工轉自動化指令碼)JMeter指令碼
- 利用tox打造自動自動化測試框架框架
- UI 自動化框架 yaml 大法UI框架YAML
- 基於Python的介面自動化-unittest測試框架和ddt資料驅動Python框架
- T框架介紹(自動化測試框架)框架
- 『居善地』介面測試 — 7、介面自動化測試框架的設計與實現框架
- 基於Python+requests搭建的自動化框架-實現流程化的介面串聯Python框架
- protobuf 介面自動化測試摸索