12 web 自动化之基于关键字+数据驱动-反射自动化框架搭建
文章目录
- 一、如何实现一条用例,实现覆盖所有用例的测试
- 1、结合数据驱动:编辑一条用例,外部导入数据实现循环测试
- 2、用例体:实现不同用例的操作步骤+对应的断言
- 二、实战
- 1、项目路径总览
- 2、common 文件夹下的代码文件
- 3、keywords 文件夹下的代码文件
- 4、testcases 文件夹下的代码文件
- 4、testdata 文件夹下的 case_data.xlsx 文件
- 5、config.py 文件
- 三、web 自动化测试完结-项目代码(总)
一、如何实现一条用例,实现覆盖所有用例的测试
1、结合数据驱动:编辑一条用例,外部导入数据实现循环测试
2、用例体:实现不同用例的操作步骤+对应的断言
- 封装对应的方法,可以执行所有用例的操作步骤+断言
二、实战
友情提示,可先看下面两篇文章,以便更好理解本篇文章:
- 【09 web 自动化之 KDT 关键字驱动详解 - CSDN App】
- 【11 web 自动化之 DDT 数据驱动详解 - CSDN App】
自动化测试框架实现与意义:
- 通过读取 excel 数据,进行数据驱动自动化测试
- 通过反射函数,实现关键字驱动
- 即使不懂代码的人,也能通过编辑 excel 数据进行测试
下述项目基本实现:
- 先通过读取用例汇总统计表中的“是否执行”来加载要执行的测试用例
- 通过要执行的测试用例名称来找到对应的工作表
- 按照测试用例工作表中的测试步骤,来通过反射函数进行一一执行
1、项目路径总览
2、common 文件夹下的代码文件
2.1 excel_operator.py 文件
是对 excel 操作进行封装的方法
import os.path import time import openpyxl from TestKDT import config from openpyxl.styles import Font,PatternFill,colors class 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).value if is_execute=="y": case_name = cases_sheet.cell(row, config.case_name).value cases_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).value if 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_fill else: case_sheet.cell(row, col).fill = green_fill self.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).value if col_case_name == case_name: # 获取执行的用例 case_name = cases_sheet.cell(row, config.case_name).value sheet = 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_fill else: cases_sheet.cell(row, col).value = 'PASS' cases_sheet.cell(row, col).fill = green_fill self.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).value values.append(step_col_value) return values def 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_time if __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 config class FrameLogger: def get_logger(self): # 创建日志器 logger = logging.getLogger("logger") # 日志输出当前级别及以上级别的信息,默认日志输出最低级别是warning if 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 log class 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}浏览器失败") raise def 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}存在!!!") raise def 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}]语句,定位元素失败!!!") raise return el def 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) raise def 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) raise def 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) raise def 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.text self.logger.info(f"在[{page_name}]页面,元素{loc}文本内容获取成功!") except: self.logger.error(f"在[{page_name}]页面,元素{loc}文本内容获取失败!") # 失败截图 self.save_screenshot(page_name) raise if fact == expect: pass else: 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: # 当前执行步骤为 FAIL self.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
- 封装对应的方法,可以执行所有用例的操作步骤+断言
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。