12 web 自動化之基于關鍵字+數據驅動-反射自動化框架搭建

文章目錄

      • 一、如何實現一條用例,實現覆蓋所有用例的測試
        • 1、結合數據驅動:編輯一條用例,外部導入數據實現循環測試
        • 2、用例體:實現不同用例的操作步驟+對應的斷言
      • 二、實戰
        • 1、項目路徑總覽
        • 2、common 文件夾下的代碼文件
        • 3、keywords 文件夾下的代碼文件
        • 4、testcases 文件夾下的代碼文件
        • 4、testdata 文件夾下的 case_data.xlsx 文件
        • 5、config.py 文件
      • 三、web 自動化測試完結-項目代碼(總)

一、如何實現一條用例,實現覆蓋所有用例的測試

1、結合數據驅動:編輯一條用例,外部導入數據實現循環測試
2、用例體:實現不同用例的操作步驟+對應的斷言
  • 封裝對應的方法,可以執行所有用例的操作步驟+斷言

二、實戰

自動化測試框架實現與意義:

  • 通過讀取 excel 數據,進行數據驅動自動化測試
  • 通過反射函數,實現關鍵字驅動
  • 即使不懂代碼的人,也能通過編輯 excel 數據進行測試

下述項目基本實現:

  • 先通過讀取用例匯總統計表中的“是否執行”來加載要執行的測試用例
  • 通過要執行的測試用例名稱來找到對應的工作表
  • 按照測試用例工作表中的測試步驟,來通過反射函數進行一一執行
1、項目路徑總覽

2、common 文件夾下的代碼文件

2.1 excel_operator.py 文件
是對 excel 操作進行封裝的方法

import os.path
import timeimport openpyxl
from TestKDT import config
from openpyxl.styles import Font,PatternFill,colorsclass ExcelOperator:"""操作 excel 文件"""def __init__(self,filename=os.path.join(config.testdata_dir,"case_data.xlsx")):# 獲取到測試用例 excel 的文件路徑self.file_path = filename# 獲取到測試用例 excel 工作簿self.wk = openpyxl.load_workbook(filename)def get_case_data(self):# """獲取 excel 工作簿中所有工作表的數據"""# self.sheetnames = self.wk.sheetnames"""獲取 excel 工作簿中要執行的用例工作表的數據"""self.sheetnames = self.get_cases_name()values= []# 循環每個工作表for sheet_name in self.sheetnames:# 獲取某個工作表某個區間列的數據value = self.get_startcol_endcol_value(sheet_name)case_data = {'case_name': sheet_name, 'steps_data': value}values.append(case_data)return values# 獲取執行用例的工作表名稱def get_cases_name(self):# 獲取匯總用例的工作表cases_sheet = self.wk[config.cases_sheet_name]cases_name = []# 根據是否執行,取到用例的名稱for row in range(2,cases_sheet.max_row+1):# 循環匯總表每一行數據is_execute = cases_sheet.cell(row, config.case_is_execute).valueif is_execute=="y":case_name = cases_sheet.cell(row, config.case_name).valuecases_name.append(case_name)return cases_name# 獲取某個工作表某個區間列的數據def get_startcol_endcol_value(self,sheetname,startcol=config.keyword_col,endcol=config.action_col):# 獲取工作表sheet = self.wk[sheetname]values = []# 循環對應工作表中的每一行數據for row in range(2,sheet.max_row+1):step_data = []for col in range(startcol,endcol+1):value = sheet.cell(row=row,column=col).valueif value is not None:step_data.append(value)values.append(step_data)return values# 將測試步驟的結果寫入 excel 文件的用例工作表中def write_step_result(self, sheet_name, row, col, result):"""寫入測試步驟的結果"""case_sheet = self.wk[sheet_name]# 寫入每步操作步驟結束時間self.write_current_time(case_sheet,row,config.step_end_time)# 寫入測試步驟的結果case_sheet.cell(row, col).value = result# 顏色填充 綠色通過 紅色失敗red_fill = PatternFill(fill_type="solid", fgColor="00FF0000")green_fill = PatternFill(fill_type="solid", fgColor="0000FF00")if result == 'FAIL':case_sheet.cell(row, col).fill = red_fillelse:case_sheet.cell(row, col).fill = green_fillself.wk.save(self.file_path)# 將測試用例的結果寫入 excel 文件的用例匯總表中def write_cases_result(self, case_name, sheet_name=config.cases_sheet_name, col=config.case_result,):"""寫入測試用例的結果"""cases_sheet = self.wk[sheet_name]for row in range(2,cases_sheet.max_row+1):# 循環匯總表的每一行col_case_name = cases_sheet.cell(row, config.case_name).valueif col_case_name == case_name:# 獲取執行的用例case_name = cases_sheet.cell(row, config.case_name).valuesheet = self.wk[case_name]# 寫入每條測試用例的結束時間self.write_current_time(cases_sheet, row, config.case_end_time)# 獲取每條執行用例的結果steps_result = self.get_sheet_col_value(sheet=sheet, col=config.step_result)# 顏色填充 綠色通過 紅色失敗red_fill = PatternFill(fill_type="solid", fgColor="00FF0000")green_fill = PatternFill(fill_type="solid", fgColor="0000FF00")# 將結果寫入匯總表中if 'FAIL' in steps_result:cases_sheet.cell(row, col).value = 'FAIL'cases_sheet.cell(row, col).fill = red_fillelse:cases_sheet.cell(row, col).value = 'PASS'cases_sheet.cell(row, col).fill = green_fillself.wk.save(self.file_path)def get_sheet_col_value(self, sheet, col):"""獲取某個工作表某列的所有數據"""values = []for row in range(2, sheet.max_row + 1):step_col_value = sheet.cell(row, col).valuevalues.append(step_col_value)return valuesdef write_current_time(self, sheet, row, col):"""將當前時間寫入某個表格中"""current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())sheet.cell(row, col).value = current_timeif __name__ == '__main__':# print(ExcelOperator().get_startcol_endcol_value("登錄",3,6))print(ExcelOperator().get_cases_name())

2.2、logger.py 文件
和之前 POM 的日志一樣

import logging
import os
import time
from TestKDT import configclass FrameLogger:def get_logger(self):# 創建日志器logger = logging.getLogger("logger")# 日志輸出當前級別及以上級別的信息,默認日志輸出最低級別是warningif not logger.handlers:logger.setLevel(logging.INFO)# 創建控制臺處理器----》輸出控制臺SH = logging.StreamHandler()# 創建文件處理器----》輸出文件log_path = os.path.join(config.logs_dir, f"log_{time.strftime('%Y%m%d%H%M%S', time.localtime())}.txt")FH = logging.FileHandler(log_path,mode="w",encoding="utf-8")# 日志包含哪些內容    時間  文件  日志級別 :事件描述/問題描述formatter = logging.Formatter(fmt="[%(asctime)s] [%(filename)s] %(levelname)s :%(message)s",datefmt='%Y/%m/%d %H:%M:%S')logger.addHandler(SH)logger.addHandler(FH)SH.setFormatter(formatter)FH.setFormatter(formatter)return logger
3、keywords 文件夾下的代碼文件

3.1 library.py 文件
是對各種關鍵字函數的封裝

import os
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from TestKDT import config
from TestKDT.common.logger import FrameLogger as logclass Library:# 登錄用例 = 多個操作步驟組成 基于每個操作步驟封裝對應的關鍵字函數# 登錄用例:# 1、打開瀏覽器- 關鍵字函數- open_browser()# 2、加載項目地址- 關鍵字函數- load_url()# 3、輸入用戶名- 關鍵字函數- input()# 4、輸入密碼- 關鍵字函數- input()# 5、點擊登錄- 關鍵字函數- click()def __init__(self):self.logger = log().get_logger()def open_browser(self,browser):"""打開瀏覽器"""# 傳入的瀏覽器參數保持首字母大寫browser = browser.capitalize()# 獲取不同類型的瀏覽器驅動try:self.driver = getattr(webdriver, browser)()self.logger.info(f"打開{browser}瀏覽器成功")except:self.logger.error(f"打開{browser}瀏覽器失敗")raisedef load_url(self, url):"""加載地址"""try:self.driver.get(url)self.logger.info(f"加載項目地址{url}成功")except:self.logger.error(f"加載項目地址{url}失敗")raise# 等待元素可見def wait_ele_visibility(self, page_name, loc, timeout=15, poll_fre=0.5):try:WebDriverWait(self.driver, timeout, poll_fre).until(EC.visibility_of_element_located(loc))# WebElement對象self.logger.info(f"在[{page_name}]頁面,找到元素:{loc}可見")except:self.logger.error(f"在[{page_name}]頁面,未找到元素:{loc}可見!!!")raise# 等待元素存在def wait_ele_presence(self, page_name, loc, timeout=15, poll_fre=0.5):try:WebDriverWait(self.driver, timeout, poll_fre).until(EC.presence_of_element_located(loc))self.logger.info(f"在[{page_name}]頁面,找到元素:{loc}存在")except:self.logger.error(f"在[{page_name}]頁面,未找到元素:{loc}存在!!!")raisedef locator(self, page_name, by_type, express):# 定位元素try:el = self.driver.find_element(by_type, express)self.logger.info(f"在[{page_name}]頁面,通過[{by_type}]方法和[{express}]語句,定位元素成功")except:self.save_screenshot(by_type)self.logger.error(f"在[{page_name}]頁面,通過[{by_type}]方法和[{express}]語句,定位元素失敗!!!")raisereturn eldef input(self, page_name, by_type, express, text):"""輸入"""loc = (by_type, express)try:self.wait_ele_visibility(page_name, loc)self.locator(page_name,by_type, express).send_keys(text)self.logger.info(f"在[{page_name}]頁面,元素{loc}輸入:{text} 成功!")except:self.logger.error(f"在[{page_name}]頁面,元素{loc}輸入失敗!")# 失敗截圖self.save_screenshot(page_name)raisedef click(self, page_name, by_type, express):"""點擊"""loc = (by_type, express)try:self.wait_ele_visibility(page_name, loc)self.locator(page_name,by_type, express).click()self.logger.info(f"在[{page_name}]頁面,元素{loc}點擊成功!")except:self.logger.error(f"在[{page_name}]頁面,元素{loc}點擊失敗!")# 失敗截圖self.save_screenshot(page_name)raisedef move_element(self, page_name, by_type, express):"""移動鼠標"""loc = (by_type, express)try:self.wait_ele_visibility(page_name, loc)el = self.locator(page_name, by_type, express)# 將鼠標移到元素上ActionChains(self.driver).move_to_element(el).perform()self.logger.info(f"在[{page_name}]頁面,鼠標移到元素{loc}成功!")except:self.logger.error(f"在[{page_name}]頁面,鼠標移到元素{loc}失敗!")# 失敗截圖self.save_screenshot(page_name)raisedef assert_text(self,page_name, by_type, express, expect):"""斷言"""loc = (by_type, express)try:self.wait_ele_visibility(page_name, loc)el = self.locator(page_name, by_type, express)fact = el.textself.logger.info(f"在[{page_name}]頁面,元素{loc}文本內容獲取成功!")except:self.logger.error(f"在[{page_name}]頁面,元素{loc}文本內容獲取失敗!")# 失敗截圖self.save_screenshot(page_name)raiseif fact == expect:passelse:raise Exception(f"在[{page_name}]頁面,斷言失敗,assertText:{fact} != {expect}")def save_screenshot(self,img_name):file_name = os.path.join(config.screenshots_dir, img_name+'.png')self.driver.save_screenshot(file_name)self.logger.error(f"失敗截圖,截取當前網頁,存儲的路徑:{file_name}")# 封裝方法,可以調用當前類下的所有關鍵字函數# *args:不定長參數def run(self,keyword,*args):print(keyword, args)# 實現打開瀏覽器# keyword = "open_browser"# args = ("edge",)# 調用關鍵字函數,基于反射getattr(self, keyword)(*args)
4、testcases 文件夾下的代碼文件

4.1 test_case.py 文件
編寫測試用例

import time
import unittest
from selenium.webdriver.common.by import By
from TestKDT.keywords.library import Library
from ddt import ddt,data,file_data,unpack
from TestKDT.common.excel_operator import ExcelOperator
from TestKDT import config@ddt
class TestCase01(unittest.TestCase):# 如何實現一條用例,實現覆蓋所有用例的測試# 每條用例的數據: 關鍵字函數 + 測試數據# case_data = [["open_browser","edge"],["load_url","http://116.62.63.211/shop/user/logininfo.html"],#               ["input",(By.NAME, "accounts"), "hc_test"],#               ["input",(By.XPATH, '//input[@type="password"]'),"hctest123"],#               ["click",(By.XPATH, '//button[text()="登錄"]')]]excel = ExcelOperator()case_data = excel.get_case_data()@data(*case_data)def test_cases(self,case_data):# 打印每條用例的數據print(case_data)case_name = case_data['case_name']steps_data = case_data['steps_data']# 用例體 = 操作步驟+ 斷言# 封裝對應的方法,可以執行所有用例的操作步驟 + 斷言lib = Library()for index, step_data in enumerate(steps_data):try:# 執行用例的操作步驟lib.run(*step_data)# 當前執行步驟為 PASS# index  0  行數 2  因為第一行不是測試數據,而是列說明self.excel.write_step_result(sheet_name=case_name, row=index+2, col=config.step_result, result="PASS")except Exception as error:# 當前執行步驟為 FAILself.excel.write_step_result(sheet_name=case_name, row=index+2, col=config.step_result, result="FAIL")self.excel.write_cases_result(case_name)
4、testdata 文件夾下的 case_data.xlsx 文件
  • 4.1 用例匯總統計
  • 4.2 登錄成功
  • 4.3 登錄失敗-1
  • 4.4 登錄失敗-2
5、config.py 文件

是項目的路徑以及其他數據內容

import os# 根路徑
base_dir = os.path.dirname(os.path.abspath(__file__))
# 用例路徑
testcases_dir = os.path.join(base_dir, 'testcases')
# 數據路徑
testdata_dir = os.path.join(base_dir, 'testdata')
# 測試報告路徑
reports_dir = os.path.join(base_dir, 'outputs/reports')
# 日志路徑
logs_dir = os.path.join(base_dir, 'outputs/logs')
# 失敗截圖
screenshots_dir = os.path.join(base_dir, 'outputs/screenshots')
# 測試用例 excel 中關鍵字所在列
keyword_col = 3
# 測試用例 excel 中操作值所在列
action_col = 7
# 用例匯總表名稱
cases_sheet_name = "用例匯總統計"
# 用例匯總表中是否執行所在列數
case_is_execute = 5
# 用例匯總表中用例名所在列數
case_name = 2
# 用例匯總表中測試結果所在列數
case_result = 7
# 用例匯總表中測試結束時間所在列數
case_end_time = 6
# 用例工作表中執行結果所在列數
step_result = 9
# 用例工作表中執行時間所在列數
step_end_time = 8# ---調試
print(testdata_dir)

三、web 自動化測試完結-項目代碼(總)

Test-Web.zip

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/81325.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/81325.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/81325.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Ubuntu shell指定conda的python環境啟動腳本

Ubuntu shell指定conda的python環境啟動腳本。 通過指令,獲取目前系統的conda虛擬python環境 conda info -e 如下圖所示,為我自己電腦的python環境 # conda environments: # base * /home/ubuntu/miniconda3 kitti …

博客系統技術需求文檔(基于 Flask)

以下內容是AI基于要求生成的技術文檔,僅供參考~ 🧱 一、系統架構設計概覽 層級 內容 前端層 HTML Jinja2 模板引擎,集成 Markdown 編輯器、代碼高亮 后端層 Flask 框架,RESTful 風格,Jinja2 渲染 數據庫 SQLi…

【Linux 學習計劃】-- 權限

目錄 權限是什么 權限的本質 權限(用戶)的修改 權限的匹配機制 目錄的權限 初始權限(文件和目錄) 粘滯位 結語 權限是什么 在現實世界中就有權限的概念,也就是,一部分人能做但是其他沒有相關身份的…

okcc呼叫中心系統搭建的方案方式

傳統企業呼叫中心多采用 PC和手機軟件,很難與客戶保持良好的溝通。因此,需要建設一套呼叫中心系統來實現與客戶實時有效溝通。那么,呼叫中心搭建的方案方式有哪些呢?下面詳細介紹一下。 呼叫中心系統的搭建方式需根據企業規模、預算和業務需…

前端最新面試題及答案 (2025)

前端最新面試題及答案 (2025) JavaScript 核心 1. ES6+ 新特性 問題: 請解釋 ES6 中 let/const 與 var 的區別,以及箭頭函數的特點。 答案: let/const vs var: 作用域: let/const 是塊級作用域,var 是函數作用域 變量提升: var會提升變量,let/const不會(有暫時性死區) 重…

傳統輪椅逆襲!RDK + 激光雷達如何重塑出行體驗?

為滿足特殊群體智能化出行需求,攻克傳統輪椅技術短板,本項目研發了一款智能輪椅。該輪椅借助攝像頭與激光雷達,精準感知環境、檢測障礙物;融合激光 SLAM 技術和互聯網地圖,實現室內外無縫導航與自主避障;提…

go-中間件的使用

中間件介紹 Gin框架允許開發者在處理請求的過程中加入用戶自己的鉤子(Hook)函數這個鉤子函數就是中間件,中間件適合處理一些公共的業務邏輯比如登錄認證,權限校驗,數據分頁,記錄日志,耗時統計 1.定義全局中間件 pac…

【Linux】動靜態庫鏈接原理

📝前言: 這篇文章我們來講講Linux——動靜態庫鏈接原理 🎬個人簡介:努力學習ing 📋個人專欄:Linux 🎀CSDN主頁 愚潤求學 🌄其他專欄:C學習筆記,C語言入門基礎…

第八節第三部分:認識枚舉、枚舉的作用和應用場景

認識枚舉 枚舉的概述 枚舉的特點 枚舉的應用場景 代碼: 代碼一:認識枚舉 A(枚舉) package com.d6_enum;public enum A {//注意:枚舉類的第一行必須羅列的是枚舉對象的名字X,Y,Z;private String name;public String…

Android framework 中間件開發(二)

上篇文章中我們講述了怎么去開發中間件 Android framework 中間件開發(一) 這篇我們講一下怎么打包中間件給外部應用使用 目錄 1.新建項目 2.編寫jar包代碼 3.打包jar包 4.使用jar包 我們可以直接將系統編譯出來的framework的jar包拿出來直接用,但是為了安全起見,防止用戶調用…

FC7300 IO 無法正常輸出高低電平問題排查

現象:Port、Dio配置正常的情況下,IO寫或者翻轉函數正常執行后,IO電平未按照預期切換電平。 排查: 第一步:檢查PORTx_PCRy寄存器值: DWP: 域寫保護:此字段指示允許哪個內核或 DMA 寫…

7 個正則化算法完整總結

哈嘍!我是我不是小upper~之前和大家聊過各類算法的優缺點,還有回歸算法的總結,今天咱們來深入聊聊正則化算法!這可是解決機器學習里 “過擬合” 難題的關鍵技術 —— 想象一下,模型就像個死記硬背的學生&am…

如何有效的開展接口自動化測試?

🍅 點擊文末小卡片,免費獲取軟件測試全套資料,資料在手,漲薪更快 一、簡介 接口自動化測試是指使用自動化測試工具和腳本對軟件系統中的接口進行測試的過程。其目的是在軟件開發過程中,通過對接口的自動化測試來提高測…

我設計的一個安全的 web 系統用戶密碼管理流程

作為一名有多年經驗的前端,在剛開始學習web后端的時候,就對如何設計一個安全的 web 系統用戶密碼管理流程有很多疑問。之前自己也實踐過幾種方法,但一直覺得不是十分安全。 我們知道,用戶在注冊或登錄界面填寫的密碼是明文的&…

煉丹學習筆記3---ubuntu2004部署運行openpcdet記錄

前言 環境 cuda 11.3 python 3.8 ubuntu2004 一、cuda環境檢測 ylhy:~/code_ws/OpenPCDet/tools$ nvcc -V nvcc: NVIDIA (R) Cuda compiler driver Copyright (c) 2005-2021 NVIDIA Corporation Built on Sun_Mar_21_19:15:46_PDT_2021 Cuda compilation tools, release 11.3…

在 Linux 系統中過濾文件中的字符串

在 Linux 系統中過濾文件中的字符串,可以使用多種命令行工具實現。以下是幾種常見方法及詳細說明: 一、使用 grep 命令(最常用) grep 是 Linux 中最強大的文本搜索工具,支持正則表達式。 基礎語法: grep…

基于PXIE 總線架構的Kintex UltraScale 系列FPGA 高性能數據預處理板卡

基于PXIE 總線架構的Kintex UltraScale 系列FPGA 高性能數據預處理板卡 一款基于3U PXIE 總線架構的高性能數據預處理FMC 載板,板卡具有1 個FMC(HPC)接口,1 個X8 GTH 背板互聯接口,可以實現1 路PCIe x8。板卡采用Xili…

Java 使用 PDFBox 提取 PDF 文本并統計關鍵詞出現次數(附Demo)

目錄 前言1. 基本知識2. 在線URL2.1 英文2.2 混合 3. 實戰 前言 爬蟲神器,無代碼爬取,就來:bright.cn Java基本知識: java框架 零基礎從入門到精通的學習路線 附開源項目面經等(超全)【Java項目】實戰CRUD…

Vue百日學習計劃Day16-18天詳細計劃-Gemini版

重要提示: 番茄時鐘: 每個番茄鐘為25分鐘學習,之后休息5分鐘。每完成4個番茄鐘,進行一次15-30分鐘的長休息。動手實踐: DOM 操作和事件處理的理解高度依賴于實際編碼。請務必在瀏覽器中創建 HTML 頁面,并配…

SearchClassUtil

路徑掃描工具SearchClassUtil,用于掃描指定包(XXXX)下的所有.class文件,并將它們的全限定類名(如tomcat.SearchClassUtil)收集到列表中返回。該工具使用遞歸文件遍歷和反射機制,是實現 Spring 框…