Python 中 openpyxl 模塊封裝,讀寫 Excel 文件中自動化測試用例

每每咱們在自動化測試彙總,會將數據放在 Excel 文件、CSV文件、數據庫數據庫

Python中處理 excel 數據的模塊很是多,好比: xlxd(只讀)、xlwd(只寫)、openpyxl(可讀寫)app

咱們會採用數據驅動思想,使用 openpyxl 當中的 load_workbook 來處理已存在的 Excel 文件數據,只能讀寫已 .xlsx 爲拓展名的文件;函數

以 .xlsx 爲拓展名的文件,爲一個 Excel 文件對象,一個excel對象中, 每每會有多個表單,一個表單中,有多個單元格對象;測試

  • 從 excel 文件中獲取的整數爲int類型、獲取的小數爲float類型
  • 除了數字類型之外, 獲取的數據所有爲字符串類
  • 若是是空的單元格不寫任何內容,讀取的是空類型,
  • 在單元各類寫入 FALSE 顯示爲大寫,格式爲bool,跟單元格的格式有關係

問:對excel相關操做使用類來封裝? 封裝有什麼好處呢?spa

  • 痛點:
    • 每一個接口每次都要打開文件,定位表單,獲取數據,若是有100個那麼每一個都須要這幾步
  • 封裝好處:
    • 利於擴展、更簡潔可讀性好,讓程序的拓展性更好,讓代碼更加簡潔,複用性高
    • 封裝後只要導入封裝好的類,而後指定Excel文件名和表單名,就可以獲取到全部的測試用例就兩行代碼

1、基本的使用excel

Excel 文件和下面的py文件代碼必定要在同一個文件夾內,否則須要指定具體的 Excel 文件路徑-------你們都是大佬我就很少說了code

讀取數據不須要關閉文件,寫入必須關閉文件;orm

from openpyxl import load_workbook


# 第一步. 打開excel文件:使用load_workbook(譯:樓的個人不可)傳入文件名
wb = load_workbook("cases.xlsx")    # 返回建立一個Workbook的對象, 至關是一個excel文件

# 第二步. 定位表單兩種方式   
# active(譯:艾克體舞)是默認第一個表單
# ws = wb.active  # 默認獲取第一個激活的表單, 會建立一個Worksheet對象, 至關於一個表單

# 也能夠指定表單
ws = wb['multiply']

# 第三步. 定位單元格 cell(譯:賽歐),row:(譯:肉)行、column:(譯:犒勞木)列
one_cell = ws.cell(row=2, column=2)     # 會建立一個Cell對象, 至關於一個單元格

# 使用 Cell(譯:賽歐)對象中的value屬性, 能獲取單元格中的值
# print(one_cell.value)

# 方法一: 定位單元格後,使用value屬性,將數據寫入到指定的單元格
one_cell.value = "休想"   # 修改單元格的值

# 方法二: 定位表單,使用cell方法,將數據寫入到指定的單元格
ws.cell(row=2, column=3, value="休想")

# 保存excel文件     save(譯:賽烏)
# 寫入若是報錯:PermissionError: [Errno 13] Permission denied: 'cases.xlsx' ,必定是excel文件未關閉
wb.save("cases.xlsx")

Excel 文件及打印結果:對象

   

2、獲取下面表單中數據blog

方法一:cell  方法:

  ---不推薦使用,由於只能獲取固定的行到行、列到列之間的數據

  

from openpyxl import load_workbook  # 對已經存在的excel進行讀寫操做

# 1. 打開excel文件
wb = load_workbook("cases.xlsx")    # 會建立一個Workbook的對象, 是一個excel文件

# 2. 定位表單
ws = wb['aaa']

# 3. 定位單元格
# 方法一:獲取表單中數據:使用ws(譯:我可誰特)當中的cell(譯:賽歐)方法
# range(譯:軟解)
# min_row(譯:敏.繞)表明最小行號:max_row(譯:馬克思.肉):最大行號
# min_column(譯:敏.犒勞木)最小列號、max_column(譯:敏.犒勞木):最大列號

for row in range(ws.min_row+1, ws.max_row+1):           # 獲取行號
    for col in range(ws.min_column, ws.max_column+1):   # 獲取列號
        data = ws.cell(row, col).value                  # 獲取值,使用value屬性
        print("值爲: {}\n類型爲: {}".format(data, type(data)))   # 打印結果

代碼執行結果文檔第一行:

  

方法二:使用 load_workbook 中 iter_rows(譯:艾特.肉死)方法 + zip 函數 獲取表單中數據

  -----推薦使用這用,在自動化測試過程當中每執行一條測試用例,均可以使用表頭來獲取具體的值

from openpyxl import load_workbook  # 對已經存在的excel進行讀寫操做

# 1. 打開excel文件
wb = load_workbook("cases.xlsx")    # 會建立一個Workbook的對象, 是一個excel文件

# 2. 定位表單
ws = wb['aaa']

# min_row(譯:敏.繞)表明最小行號:max_row(譯:馬克思.肉):最大行號
# min_column(譯:敏.犒勞木)最小列號、max_column(譯:敏.犒勞木):最大列號

# 3. 定位單元格
# 方法二:使用 load_workbook 中 iter_rows(譯:艾特.肉死)方法獲取表單中數據
# openpyxl 版本爲2.6以上,要不沒有參數:values_only
# 獲取的是單元格位置 使用 values_only = False 屬性默認獲取單元格對象
# 獲取的是單元格位置 使用 values_only = True 後獲取的是單元格的值

# 獲取表頭元祖,表頭位置爲0,表頭爲第一行,最小行號能夠不寫1,由於最大行號是1
# 結果爲生成器對象,須要使用 tuple 轉換爲元祖,轉換後爲嵌套元祖的元祖
head_data_tuple = tuple(ws.iter_rows(min_row=1, max_row=1, values_only=True))[0]
print(head_data_tuple)

# 獲取除表頭外測試用例數據,和獲取表頭同樣,最大行,最小列能夠不寫
for one_tuple in tuple(ws.iter_rows(min_row=2, max_row=5, min_col=1, max_col=7, values_only=True)):
    print(one_tuple)

# 表頭和測試數據結果
# ('case_id', 'title', 'l_data', 'r_data', 'expected', 'actual', 'result')
# (1, '負數與負數相乘', -2, -4, 8, None, None)
# (2, '負數與正數相乘', -3, 4, 12, None, None)
# (3, '零與零相乘', 0, 0, 0, None, None)
# (4, '正數與正數相乘', 5, 3, -15, None, None)

head_data_tuple1 = tuple(ws.iter_rows(min_row=1, max_row=1, values_only=True))[0]
one_list1 = []
for one_tuple1 in tuple(ws.iter_rows(min_row=2, max_row=5, min_col=1, max_col=7, values_only=True)):
    # 表頭的元祖和數據元祖,使用 zip 方法進行轉換(返回zip的生成器對象)
    # 在使用dict(譯:迪克特)轉換成字典
    # 使用append(譯:額噴的)添加到列表當中,獲取到一個嵌套字典的列表
    one_list1.append(dict(zip(head_data_tuple1, one_tuple1)))
print(one_list1)     # 打印結果

# 結果:
# [{'case_id': 1, 'title': '負數與負數相乘', 'l_data': -2, 'r_data': -4, 'expected': 8, 'actual': None, 'result': None}, 
#  {'case_id': 2, 'title': '負數與正數相乘', 'l_data': -3, 'r_data': 4, 'expected': 12, 'actual': None, 'result': None}, 
#  {'case_id': 3, 'title': '零與零相乘', 'l_data': 0, 'r_data': 0, 'expected': 0, 'actual': None, 'result': None}, 
#  {'case_id': 4, 'title': '正數與正數相乘', 'l_data': 5, 'r_data': 3, 'expected': -15, 'actual': None, 'result': None}]

3、openpyxl 模塊的封裝:

 

from openpyxl import load_workbook


class HandleExcel:
    """
    封裝excel文件處理類
    """
    def __init__(self, filename, sheetname=None):
        """
        :param filename: 文件名
        :param sheetname: 表單名,若是表單名只有一個能夠設置爲默認值
        """
        self.filename = filename
        self.sheetname = sheetname

    def get_cases(self):
        """
        獲取全部的測試用例,實例方法
        :return:
        """
        # 打開文件:使用load_workbook(樓的個人不可)傳入文件名
        wb = load_workbook(self.filename)   # 返回建立一個Workbook的對象, 至關是一個excel文件
        if self.sheetname is None:          # 定位表單,判斷是否制定表單默認空,爲第一個表單
            ws = wb.active                  # active 獲取第一個表單
        else:
            ws = wb[self.sheetname]         # 不然獲取指定的表單
        # min_row=最小行號,max_row=最大行號(能夠不寫)
        # min_col=最小列號,max_col=最大列號
        # values_only=獲取單元格的值
        # 獲取表頭的信息,使用iter_rows(艾特木肉絲)方法,嵌套元祖的元祖,省略最小行號
        head_data_tuple = tuple(ws.iter_rows(max_row=1, values_only=True))[0]
        one_list = []
        for one_tuple in tuple(ws.iter_rows(min_row=2, values_only=True)):  # 不須要表頭最小行號爲2,不須要最大行號,最大最小列號
            # zip函數將表頭的元祖與每一行用例所在的元祖進行拼接,dict轉換爲字典後,添加到列表當中one_list = []
            one_list.append(dict(zip(head_data_tuple, one_tuple)))
        return one_list

    def get_one_case(self, row):
        """
        獲取某一條測試用例
        :param row: 行號
        :return:
        """
        return self.get_cases()[row - 1]

    def write_result(self, row, actual, result):
        """
        寫入數據到測試用例指定的行列中
        :param row: 行號
        :param actual: 實際結果
        :param result: 用例執行的結果(Pass或者Fail)
        :return:
        """
        # 同一個Workbook對象, 若是將數據寫入到多個表單中, 那麼只有最後一個表單能寫入成功,須要建立不一樣的對象
        other_wb = load_workbook(self.filename)     # 建立對象 = 打開一個文件
        if self.sheetname is None:
            other_ws = other_wb.active
        else:
            other_ws = other_wb[self.sheetname]
        # 寫入
        if isinstance(row, int) and (2 <= row <= other_ws.max_row):     # 不能修改表頭,下一行開始
            other_ws.cell(row=row, column=6, value=actual)              # 在第六行寫入實際結果
            other_ws.cell(row=row, column=7, value=result)              # 在第七行寫入用例執行的結果
            other_wb.save(self.filename)                                # save保存文件
            other_wb.close()        # close關閉-----讀數據的時候不須要關閉,寫數據的時候可關閉或不關閉
        else:   # 若是不是整數,行號小於2,而且大於最大的行號
            print("傳入的行號有誤, 行號應爲大於1的整數")


if __name__ == '__main__':      # 本身寫的模塊本身用使用 main 函數
    filename = "cases.xlsx"
    sheetname = "Sheet1"     # 指定第二個表單名
    # 建立一個對象,filename=文件名和sheetname=表單名能夠不傳

    # do_excel = HandleExcel(filename)  # 不傳默認第一個表單

    do_excel = HandleExcel(filename, sheetname)
    # 獲取全部的測試用例cases
    cases = do_excel.get_cases()
    print(cases)
    # 寫入在第二行寫入"初心", "青檸"
    a = do_excel.write_result(2, "初心7", "青檸")
    print(a)

 

 

*******請你們尊重原創,如要轉載,請註明出處:轉載自:https://www.cnblogs.com/shouhu/   謝謝!!******* 

相關文章
相關標籤/搜索