在上一篇Python接口自動化測試系列文章:Python接口自動化淺析登錄接口測試實戰(zhàn),主要介紹接口概念、接口用例設(shè)計及登錄接口測試實戰(zhàn)。
以下主要介紹使用openpyxl模塊操作excel及結(jié)合ddt實現(xiàn)數(shù)據(jù)驅(qū)動。
在此之前,我們已經(jīng)實現(xiàn)了用unittest框架編寫測試用例,實現(xiàn)了請求接口的封裝,這樣雖然已經(jīng)可以完成接口的自動化測試,但是其復(fù)用性并不高。
我們看到每個方法(測試用例)的代碼幾乎是一模一樣的,試想一下,在我們的測試場景中,
一個登錄接口有可能會有十幾條到幾十條測試用例,如果每組數(shù)據(jù)都編寫一個方法,
這樣將會有更多的重復(fù)項代碼,不僅執(zhí)行效率不高,也不好維護(hù)。
接下來將會對框架進(jìn)行優(yōu)化,采用數(shù)據(jù)驅(qū)動方式:
openpyxl是python第三方模塊,運用openpyxl庫可以進(jìn)行excel的讀和寫。
在了解openpyxl模塊之前,我們需要先熟悉excel的結(jié)構(gòu),才能更好理解openpyxl是如何操作excel。
從外到內(nèi),首先是一個excel文件(名),打開excel之后,會看到底部有一個或多個sheet(工作簿),每個sheet里有很多單元格,總體來說,主要分為三個層級。
在opnepyxl里面,一個Excel文件對應(yīng)著一個Workbook對象, 一個Sheet對應(yīng)著一個Worksheet對象,而一個單元格對應(yīng)著一個Cell對象。了解這些之后,對openpyxl是如何操作excel就比較清楚了。
pip install openpyxl
import openpyxl if __name__ == '__main__': path = 'F:/case/test_case.xlsx' # 讀取excel文件 workbook = openpyxl.load_workbook(path) # 讀取所有sheet sheet = workbook.get_sheet_names() # 獲取某個sheet sheet = workbook[sheet[0]] # 獲取某個cell的值 cell_val = sheet.cell(row=2, column=2).value print(cell_val)
以上僅介紹openpyxl常用的語法,有興趣了解更多內(nèi)容可自行百度擴(kuò)展。
在項目下,新建一個文件夾:data,文件夾下新建一個cases.xlsx文件,用來存放測試用例。
以下,是一個簡單的登錄測試用例設(shè)計模板:
可以根據(jù)該表格生成實際結(jié)果,并將測試結(jié)果寫入(Pass、Fail)表格。
公眾號后臺回復(fù):接口測試用例模板,可以獲取完整接口測試用例Excle模板。
既然有了用例模板,我們就開始從用openpyxl模塊對excel讀寫數(shù)據(jù)。
如下,在common文件夾下,新建excel_handle.py,用于封裝操作excel的類。
excel_handle.py
import openpyxl class ExcelHandler: def __init__(self, file): self.file = file def open_excel(self, sheet_name): """打開Excel、獲取sheet""" wb = openpyxl.load_workbook(self.file) # 獲取sheet_name sheet = wb[sheet_name] return sheet def get_header(self, sheet_name): """獲取header(表頭)""" wb = self.open_excel(sheet_name) header = [] # 遍歷第一行 for i in wb[1]: # 將遍歷出來的表頭字段加入列表 header.append(i.value) return header def read_excel(self, sheet_name): """讀取所有數(shù)據(jù)""" sheet = self.open_excel(sheet_name) rows = list(sheet.rows) data = [] # 遍歷從第二行開始的每一行數(shù)據(jù) for row in rows[1:]: row_data = [] # 遍歷每一行的每個單元格 for cell in row: row_data.append(cell.value) # 通過zip函數(shù)將兩個列表合并成字典 data_dict = dict(zip(self.get_header(sheet_name),row_data)) data.append(data_dict) return data @staticmethod def write_excel(file, sheet_name, row, cloumn,data): """Excel寫入數(shù)據(jù)""" wb = openpyxl.load_workbook(file) sheet = wb[sheet_name] sheet.cell(row, cloumn).value = data wb.save(file) wb.close() if __name__ == "__main__": # 以下為測試代碼 excel = ExcelHandler('../data/cases.xlsx') data = excel.read_excel('login')
接下來結(jié)合ddt實現(xiàn)數(shù)據(jù)驅(qū)動,先簡單來介紹下ddt。
補(bǔ)充:
所謂數(shù)據(jù)驅(qū)動,就是數(shù)據(jù)的改變從而驅(qū)動自動化測試的執(zhí)行,最終引起測試結(jié)果的改變。說的直白些,就是參數(shù)化的應(yīng)用。
ddt安裝
pip install ddt
要想知道ddt到底怎么使用,我們從ddt模塊源碼中提取出三個重要的函數(shù)ddt、unpack、data。
def ddt(cls): """ Class decorator for subclasses of ``unittest.TestCase``. Apply this decorator to the test case class, and then decorate test methods with ``@data``. For each method decorated with ``@data``, this will effectively create as many methods as data items are passed as parameters to ``@data``. The names of the test methods follow the pattern ``original_test_name_{ordinal}_{data}``. ``ordinal`` is the position of the data argument, starting with 1. For data we use a string representation of the data value converted into a valid python identifier. If ``data.__name__`` exists, we use that instead. For each method decorated with ``@file_data('test_data.json')``, the decorator will try to load the test_data.json file located relative to the python file containing the method that is decorated. It will, for each ``test_name`` key create as many methods in the list of values from the ``data`` key. """ for name, func in list(cls.__dict__.items()): if hasattr(func, DATA_ATTR): for i, v in enumerate(getattr(func, DATA_ATTR)): test_name = mk_test_name(name, getattr(v, "__name__", v), i) test_data_docstring = _get_test_data_docstring(func, v) if hasattr(func, UNPACK_ATTR): if isinstance(v, tuple) or isinstance(v, list): add_test( cls, test_name, test_data_docstring, func, *v ) else: # unpack dictionary add_test( cls, test_name, test_data_docstring, func, **v ) else: add_test(cls, test_name, test_data_docstring, func, v) delattr(cls, name) elif hasattr(func, FILE_ATTR): file_attr = getattr(func, FILE_ATTR) process_file_data(cls, name, func, file_attr) delattr(cls, name) return cls def unpack(func): """ Method decorator to add unpack feature. """ setattr(func, UNPACK_ATTR, True) return func def data(*values): """ Method decorator to add to your test methods. Should be added to methods of instances of ``unittest.TestCase``. """ global index_len index_len = len(str(len(values))) return idata(values)
裝飾類,也就是繼承自TestCase的類。
裝飾測試方法。參數(shù)是一系列的值。
傳遞的是復(fù)雜的數(shù)據(jù)結(jié)構(gòu)時使用。比如使用元組或者列表,添加unpack之后,ddt會自動把元組或者列表對應(yīng)到多個參數(shù)上,字典也可以這樣處理;當(dāng)沒有加unpack時,方法的參數(shù)只能填一個。
知道了具體應(yīng)用后,簡單來個小例子加深理解。
test_ddt.py
import unittest import ddt # 裝飾類 @ddt.ddt class DdtDemo(unittest.TestCase): def setUp(self): pass def tearDown(self): pass # 裝飾方法 @ddt.data(("15312344578", "12345678"), ("15387654321", "12345678")) @ddt.unpack def test_ddt(self, username,password): print(username,password) if __name__ == '__main__': unittest.main(verbosity=2)
運行結(jié)果為:
Ran 2 tests in 0.001s
OK
15312344578 12345678
15387654321 12345678
上面的例子是為了加深理解,接下來介紹excel結(jié)合ddt實現(xiàn)數(shù)據(jù)驅(qū)動,優(yōu)化之前的test_login.py模塊。
test_login.py
import unittest from common.requests_handler import RequestsHandler from common.excel_handler import ExcelHandler import ddt import json @ddt.ddt class TestLogin(unittest.TestCase): # 讀取excel中的數(shù)據(jù) excel = ExcelHandler('../data/cases.xlsx') case_data = excel.read_excel('login') print(case_data) def setUp(self): # 請求類實例化 self.req = RequestsHandler() def tearDown(self): # 關(guān)閉session管理器 self.req.close_session() @ddt.data(*case_data) def test_login_success(self,items): # 請求接口 res = self.req.visit(method=items['method'],url=items['url'],json=json.loads(items['payload']), headers=json.loads(items['headers'])) try: # 斷言:預(yù)期結(jié)果與實際結(jié)果對比 self.assertEqual(res['code'], items['expected_result']) result = 'Pass' except AssertionError as e: result = 'Fail' raise e finally: # 將響應(yīng)的狀態(tài)碼,寫到excel的第9列,即寫入返回的狀態(tài)碼 TestLogin.excel.write_excel("../data/cases.xlsx", 'login', items['case_id'] + 1, 9, res['code']) # 如果斷言成功,則在第10行(測試結(jié)果)寫入Pass,否則,寫入Fail TestLogin.excel.write_excel("../data/cases.xlsx", 'login', items['case_id'] + 1, 10, result) if __name__ == '__main__': unittest.main()
整體流程如下圖:
到此這篇關(guān)于Python接口自動化淺析數(shù)據(jù)驅(qū)動原理的文章就介紹到這了,更多相關(guān)Python接口自動化數(shù)據(jù)驅(qū)動內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
標(biāo)簽:普洱 盤錦 林芝 海南 漯河 南平 大同 寧夏
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Python接口自動化淺析數(shù)據(jù)驅(qū)動原理》,本文關(guān)鍵詞 Python,接口,自動化,淺析,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。