最近接到一個接口自動化測試的case,并展開了一些調研工作,最后發(fā)現(xiàn)卖毁,使用pytest測試框架并以數(shù)據驅動的方式執(zhí)行測試用例羡藐,可以很好的實現(xiàn)自動化測試贩毕。這種方式最大的優(yōu)點在于后續(xù)進行用例維護的時候對已有的測試腳本影響很小。當然仆嗦,pytest還有以下其他優(yōu)點:
- 可以讓用戶寫出更為緊湊的測試套件辉阶;
- 涉及到的樣板代碼并不多,因此用戶能夠容易地編寫和理解各種測試瘩扼;
- 測試夾具(fixture)函數(shù)常被用來向測試函數(shù)添加某個參數(shù)谆甜,并返回不同的值。在pytest中集绰,可以通過使用一個fixture來模塊化另外一個规辱。同時也可以使用多個fixture,在無需重寫測試用例的情況下栽燕,將測試覆蓋到所有參數(shù)的組合罕袋;
- 可擴展性強改淑,pytest有許多實用的插件。例如:pytest-xdist可以在不使用其他測試器的情況下炫贤,被用于執(zhí)行并行測試溅固;pytest-rerunfailures可以在測試失敗后重新運行,而且運行次數(shù)和運行之間的延遲時間都是可以設置的兰珍;allure/pytest-html生成測試報告侍郭;
相比較其它的測試框架,比如Robot Framework(在創(chuàng)建自定義的HTML報告方面比較繁瑣掠河,頂多能用來生成xUnit格式的簡短報告)亮元、UniteTest/PyUnit(需要大量的樣板代碼),pytest更適合作為本次自動化測試的框架唠摹。
下面為大家詳細的介紹這種自動化測試的實現(xiàn)過程爆捞。
1 前期的準備工作
1.1 接口路徑表
根據接口文檔,將接口的地址和路徑以及請求方式記錄在excel表中勾拉,key:接口名稱煮甥,type:請求方式,value:接口路徑藕赞,第一行baseurl為基本路徑成肘,type不填。接口名稱建議與接口文檔中的接口名稱一致斧蜕,這樣方便檢查双霍。如果同一個接口有多種請求方式,需要重新填寫一行批销,type為相對應的請求方式洒闸。這樣記錄接口路徑和請求方式是為了方便后面的數(shù)據提取和處理。
1.2 測試用例表
測試用例表中主要記錄9列類型的數(shù)據均芽,測試模塊:將接口按照模塊進行劃分有利于問題的定位和數(shù)據的分類丘逸;
- 測試模塊:將被測接口按照功能進行模塊劃分;
- 用例編號:主要用于記錄用例的條數(shù)掀宋,建議按照模塊名稱進行命名鸣个,如:登錄模塊,用例編號為login_001,login_002布朦;
- 用例標題:記錄測試的內容囤萤;
- 前置條件:當被測接口需要其他接口的數(shù)據支撐時,在前置條件欄中填入需要的接口數(shù)據:如:login_001:token(login_001指用例編號是趴,token指該用例執(zhí)行后返回的響應參數(shù)中token字段的值)涛舍,前提條件是該接口用例在本條用例之前;
- 測試步驟:方便于模塊用例的執(zhí)行唆途;
- 請求接口:按照接口路徑表中key的命名填寫富雅,需要請求登錄接口時掸驱,就填寫上圖中表中key命名的登錄接口。請求頭部:當請求頭部中有特殊的參數(shù)時没佑,比如該接口需要身份驗證authorization字段毕贼,而該字段的數(shù)據來源于登錄接口返回的token,這種用例的請求頭部應該這樣填寫: Content-Type=application/json,Authorization=<token>蛤奢;
- 請求數(shù)據:填寫測試用例的請求數(shù)據鬼癣,按照key=value的格式記錄,如果需要其他接口的返回數(shù)據啤贩,在前置條件中加入之后待秃,再填寫請求數(shù)據中需要的返回數(shù)據即可,如:username =admin,password=zxcvbnm,token=<token>痹屹;
- 斷言:根據接口返回的數(shù)據進行斷言章郁,主要是驗證返回數(shù)據中的某個字段是否正確,也是按照key=value的格式進行填寫志衍;
2 目錄結構及運行流程
2.1 文件目錄結構
- testcase文件夾:存放測試用例表暖庄;
- api文件夾:存放接口路徑表;
- common文件夾:common文件中存放通用的數(shù)據處理的腳本楼肪,如data.py和utlis.py(主要作用是將表中的數(shù)據進行處理培廓,后面會進行詳細的說明)、config.py(測試套件的基本配置)淹辞;
- report文件夾:用于存放測試完成后生成的測試報告;
- conftest.py:屬于pytest的一種全局公用的文件俘侠,一些通用的方法可以放在conftest.py中象缀;
- pytest.ini:pytest的配置文件;
2.2 測試的運行流程
觸發(fā)自動化測試之后爷速,測試數(shù)據的提取與處理并不會使用到pytest框架央星,當把數(shù)據處理為測試套件后,按模塊分配給pytest進行執(zhí)行惫东,包括測試模塊莉给、http請求、斷言廉沮。所有模塊執(zhí)行完之后將測試結果體現(xiàn)在生成的測試報告report.html中颓遏。測試結束之后可以通過郵件或者釘釘機器人的方式通知測試或開發(fā)本次自動化測試的測試結果。
3 測試用例的實現(xiàn)過程
下面簡單介紹一下測試用例實現(xiàn)過程中部分腳本的作用滞时。
3.1 讀取excel表
使用xlrd庫讀取excel表中的內容叁幢,python中還有很多可以對excel的數(shù)據進行操作的庫,如:openpyxl坪稽、xlsxwriter曼玩;循環(huán)遍歷每一行的數(shù)據鳞骤,保存為列表并賦值給self.list_data。
# -*- coding: utf-8 -*-
import xlrd
class Excel(object):
def __init__(self, file_name):
# 讀取excel
self.wb = xlrd.open_workbook(file_name)
self.sh = self.wb.sheet_names()
self.list_data = []
def read(self):
for sheet_name in self.sh:
sheet = self.wb.sheet_by_name(sheet_name)
rows = sheet.nrows
for i in range(0, rows):
rowvalues = sheet.row_values(i)
self.list_data.append(rowvalues)
3.2 將數(shù)據格式化成測試套件
第一步將表格數(shù)據保存為列表后黍判,還不是我們需要的數(shù)據格式豫尽,這樣的數(shù)據列表不能直接使用,這里進行了一次數(shù)據的格式化顷帖。這里需要用到config.py中的case_header的配置美旧,將中文的標題換成英文,并作為字典的key值窟她。之后從第1個元素開始循環(huán)遍歷data陈症,將data中每個元素都以 [{'key1': 'value1', 'key2': 'value2'}, {}, {}, ...]的形式保存為list_dict_data并返回。
def data_to_dict(data):
"""
:param data: data_list
:return:
"""
head = []
list_dict_data = []
for d in data[0]:
d = case_header.get(d, d)
head.append(d)
for b in data[1:]:
dict_data = {}
for i in range(len(head)):
if isinstance(b[i], str):
dict_data[head[i]] = b[i].strip()
else:
dict_data[head[i]] = b[i]
list_dict_data.append(dict_data)
return list_dict_data
case_header = {
'測試模塊': 'module',
'用例編號': 'id',
'用例標題': 'title',
'前置條件': 'condition',
'測試步驟': 'step',
'請求接口': 'api',
'請求方式': 'method',
'請求頭部': 'headers',
'請求數(shù)據': 'data',
'斷言': 'assert',
'步驟結果': 'score' }
3.3 生成可執(zhí)行的測試套件
上一步已經將數(shù)據處理成了[{'key1': 'value1', 'key2': 'value2'}, {}, {}, ...]這樣的格式震糖,但是發(fā)現(xiàn)這樣的格式沒有將模塊中的用例整合到一起录肯,列表中每一個元素都是單獨的一條用例,這樣的話不利于用例的執(zhí)行吊说,所以论咏,對上一步返回的數(shù)據再進行一次處理。因為測試用例和接口路徑是保存在兩個excel表中的颁井,所以需要將兩個表的數(shù)據進行合并厅贪。首先將接口路徑表中的數(shù)據讀取出來并處理成需要的格式 {'key': {'type': 'value', 'url': 'value'}},之后按照測試步驟中的順序把測試用例保存在steps字典中雅宾。由于代碼過長养涮,下面只展示核心部分。
for d in data:
# 將請求數(shù)據和斷言數(shù)據格式化
for key in ('data', 'assert', 'headers'):
if d[key].strip():
test_data = dict()
for i in d[key].split(','):
i = i.split('=')
test_data[i[0]] = i[1]
d[key] = test_data
if d['module'].strip():
if testcase:
testsuite.append(testcase)
testcase = {}
testcase['module'] = d['module']
testcase['steps'] = []
no = str(d['step']).strip()
if no:
step = {'no': str(int(d['step']))}
for key in ('id', 'title', 'condition', 'api', 'headers', 'data', 'assert'):
if key == 'api':
step[key] = {'type': apis[d.get(key, '')]['type'],
'url': apis['baseurl']['url'] + apis[d.get(key, '')]['url']}
else:
step[key] = d.get(key, '')
testcase['steps'].append(step)
if testcase:
testsuite.append(testcase)
3.4 pytest執(zhí)行測試套件
將http請求封裝在了conftest.py中眉抬,使用pytest數(shù)據驅動的特點贯吓,在執(zhí)行測試文件test_login。py中不需要import就可以直接調用蜀变。這里只展示了發(fā)起post請求的代碼悄谐,其它類型的請求類似,pytest.fixture通過固定參數(shù)request傳遞數(shù)據库北。然后使用'標記'中的pytest.mark.parametrize進行參數(shù)化和數(shù)據驅動更靈活爬舰。在fixture中的方法里面準備測試數(shù)據和前置依賴方法,在測試方法中參數(shù)化寒瓦,測試方法調用準備數(shù)據和前置方法情屹。pytest.mark.parametrize('post_request', data, indirect=True),indirect=True是把post_request當作函數(shù)去執(zhí)行杂腰,data則是前面生成的模塊的測試用例屁商,其中包括了發(fā)起\http請求所需要的所有參數(shù)。
@pytest.fixture()
def post_request(request):
data = request.param['data']
header = request.param['headers']
url = request.param['api']['url']
no = request.param['no']
logger.info(f'request: {data}')
response = requests.request('POST', url=url, headers=header, data=json.dumps(data))
logger.info(f'response: {response.json()}')
return response, no
# -*- coding: UTF-8 -*-
import pytest
import allure
from common.data import module_data
class TestCase(object):
@allure.feature('登錄')
@pytest.mark.parametrize('post_request', module_data(module='登錄'), indirect=True)
def test_login(self, post_request):
response = post_request[0].json()
no = int(post_request[1])
assert response['msg'] == module_data(module='登錄')[no - 1]['assert']['msg']
def module_data(module):
excel = Excel(file_path.parent / 'testcase/testcase.xlsx')
excel.read()
cases = excel.list_data
test_suit = suite_cases(data_to_dict(cases))
for _ in test_suit:
if _['module'] == module:
data = _['steps']
return data
3.5 運行測試用例
可以在pytest.ini中配置執(zhí)行測試時的一些文件、類蜡镶、方法的匹配規(guī)則和常用的命令參數(shù)雾袱,執(zhí)行時只需要命令行輸入D:\py_test>pytest就可以開始執(zhí)行自動化測試。也可以不用pytest.ini配置官还,命令行執(zhí)行D:\py_test>pytest -s test_login.py --html=report/report.html芹橡,-s參數(shù):輸出所有測試用例的print信息,安裝了pytest-html插件后望伦,在執(zhí)行命令中加入--html=測試報告保存路徑林说。
pytest.ini文件配置如下:
[pytest]
# 打印print,生成保存報告
addopts = -s --html=report/report.html
# 匹配執(zhí)行文件
python_files = test_*.py
# 匹配執(zhí)行類
python_classes = Test*
# 匹配執(zhí)行方法
python_functions = test_*
3.6 結果展示
可以在ide中執(zhí)行測試用例屯伞,也可以使用命令行執(zhí)行腿箩,執(zhí)行完測試用例后,會生成一個html格式的測試報告劣摇,在瀏覽器中打開就可以查看本次自動化測試的測試結果珠移。pytest不僅支持pytest-html插件,還可以使用allure生成更加美觀的測試報告末融。下面分別展示使用pytest-html和allure生成的html測試報告钧惧,pytest-html報告中記錄的內容比較詳盡,包括了用例運行日志勾习、通過\失敗\跳過用例條數(shù)浓瞪、用例運行時間等等。allure生成的報告可讀性比較強巧婶,可以很直觀的看到測試結果乾颁。
pytest-html生成的測試報告:
allure生成的測試報告:
4 總結
整個項目完成之后,對pytest測試框架有了更深的理解艺栈。同時英岭,pytest也可以使用Jenkins將自動化測試加入到持續(xù)集成中,設置定時任務構建或者條件觸發(fā)構建等眼滤,這樣可以有效的提高測試效率巴席,也節(jié)省了人力成本历涝。當然诅需,不僅僅只有這一種實現(xiàn)方式,目前的實現(xiàn)方式還是有很多不足的地方荧库,后面會繼續(xù)進行完善和改進堰塌。如果你有什么好的建議和方法,歡迎一起進行溝通和交流分衫。
我們是行者AI场刑,我們在“AI+游戲”中不斷前行。
如果你也對游戲感興趣蚪战,對AI充滿好奇牵现,那就快來加入我們吧~