web自动化(5)——关键字驱动

news2024/10/6 22:29:30

        PO 模型会增加测试脚本的编写复杂度,尤其是当测试项目规模较大或者业务逻辑较为复杂时,需要编写大量的 Page Object 类,或者一旦我们的项目发生变动甚至更换项目时,就需要大量修改原来的代码,增加了项目的维护成本。关键字模型,更关注的是业务流程,其实很多企业也是如此,我们只需要在excel文件中讲测试用例维护好,而需要编写的脚本量非常小,如果页面有变动,只需要维护excel表格中的用例数据即可,而脚本基本不需要变动。

1. 关键字驱动

Keyword Driver Test:关键字驱动测试,建立在pom基础上,解决POM代码封装量太大的弊端。

我们在core目录中新建kdt.py,用于创建kdt类,类里面我们封装一些常用的操作,例如点击、输入、选择等

import time
from pathlib import Path

from selenium.webdriver import Chrome
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.wait import WebDriverWait


class KeyWord:
    """关键字类:用户操作指令集"""
    _split_chr = ';;;'

    def __init__(self, driver: Chrome):  # 在进行实例化是被自动调用,可以接收参数
        self.driver = driver
        self.wait = WebDriverWait(driver, 10)

    def get(self, url):
        """
        跳转指定页面
        :param url:
        :return:
        """
        self.driver.get(url)

    def find_element(self, loc: str):
        """
        元素定位:自动等待元素出现
        :return:
        """
        value, *by = loc.split(self._split_chr)  # *表示不定长参数, 将loc中通过;;;的符号进行value和by的分割
        if not by:
            by = By.XPATH  # 如果没有指定,默认定位策略是Xpath
        else:
            by = getattr(By, by[0])  # 通过反射得到By方法

        def f(driver):
            return self.driver.find_element(by, value)

        element = self.wait.until(f)
        return element

    # 点击
    def click(self, loc: str, force=False):
        """
        :param loc: 定位表达式 支持几个功能:1.可以用json传输基本数据 2.支持多种定位方法 3. 默认使用XPATH 因此选择loc类型为str
        :param force: 是否强制点击
        """
        element = self.find_element(loc)
        if force:
            # 通过js代码实现强制点击
            self.driver.execute_script("arguments[0].click()", element)
        else:
            element.click()  # 普通点击

    # 输入
    def input(self, loc, value, force=False):
        element = self.find_element(loc)
        if force:
            # 通过js代码实现强制输入
            self.driver.execute_script(f"arguments[0].value='{value}'", element)
        else:
            element.send_keys(value)  # 普通点击

    # 清空
    def clear(self, loc, force=False):
        element = self.find_element(loc)
        if force:
            # 通过js代码实现强制清空
            self.driver.execute_script(f"arguments[0].value=''", element)
        else:
            element.clear()  # 普通点击

    # 进入框架
    def iframe_enter(self, loc):
        element = self.find_element(loc)
        self.driver.switch_to.frame(element)

    # 退出框架
    def iframe_exit(self):
        self.driver.switch_to.default_content()

    # 选择
    def select(self, loc, text):
        """
        下拉选择框选择指定的选项
        text:选项的显示文本
        """
        element = self.find_element(loc)
        Select(element).select_by_visible_text(text)

    # 文件上传
    def upload(self, loc, file):
        """
        :param file: 文件路径
        """
        element = self.find_element(loc)
        path = Path(file)
        path = path.absolute()  # 相对路径转绝对路径
        element.send_keys(str(path))

    def sleep(self, x):
        time.sleep(x)

    def assert_text(self, loc, text):
        """
        断言
        :param loc:
        :param text:
        :return:
        """
        element = self.find_element(loc)
        assert element.text == text

然后在test_admin.py中新建测试用例,

def test_new_deal_by_kdt(admin_driver):
    data = {
        'name': '借款1亿买别墅',
        'shor_name': '买别墅',
        'username': 'beifan',
        'cate': '|--房产抵押标',
        'upload': r'D:\pythonProject2\temp\code.png',
        'type': '个人消费',
        'contract': '等额本息合同范本【担保】',
        'tcontract': '付息还本合同范本【普通】',
        'amount': '100000000',
        'rate': '5',
        'enddate': '30',
        'start_time': '2023-12-25 18:02:02'
    }
    wd = KeyWord(admin_driver)  # 实例化关键字类
    wd.iframe_enter('/html/frameset/frame[1]')  # 进入框架
    wd.click('//*[@id="navs"]/ul/li[2]/a')  # 点击贷款管理
    wd.iframe_exit()  # 退出框架

    wd.iframe_enter('//*[@id="menu-frame"]')  # 进入框架
    wd.click('/html/body/dl[1]/dd[1]/a')  # 点击全部贷款
    wd.iframe_exit()  # 退出框架

    wd.iframe_enter('//*[@id="main-frame"]')  # 进入框架
    wd.click('/html/body/div[2]/div[3]/input[1]')  # 点击新增贷款
    wd.input('/html/body/div[2]/form/table[1]/tbody/tr[4]/td[2]/input', data['name'])  # 贷款名称
    wd.input('/html/body/div[2]/form/table[1]/tbody/tr[5]/td[2]/input', data['shor_name'])  # 简短名称
    wd.input('/html/body/div[2]/form/table[1]/tbody/tr[6]/td[2]/input[1]', data['username'])  # 会员名称
    wd.click('//strong[text()="beifan"]')
    wd.click('//*[@id="citys_box"]/div[1]/div[2]/input[1]')  # 城市
    # 分类
    wd.select('/html/body/div[2]/form/table[1]/tbody/tr[8]/td[2]/select', data['cate'])
    # 图片上传
    wd.click('/html/body/div[2]/form/table[1]/tbody/tr[14]/td[2]/span/div[1]/div/div/button')
    wd.click('/html/body/div[6]/div[1]/div[2]/div/div[1]/ul/li[2]')
    wd.upload('//input[@type="file"]', data['upload'])
    wd.click('/html/body/div[6]/div[1]/div[3]/span[1]/input')
    # 借款用途
    wd.select('/html/body/div[2]/form/table[1]/tbody/tr[15]/td[2]/select', data['type'])
    # 借款合同范本
    wd.select('/html/body/div[2]/form/table[1]/tbody/tr[17]/td[2]/select', data['contract'])
    # 转让合同
    wd.select('/html/body/div[2]/form/table[1]/tbody/tr[18]/td[2]/select', data['tcontract'])
    # 借款金额
    wd.clear('/html/body/div[2]/form/table[1]/tbody/tr[19]/td[2]/input')
    wd.input('/html/body/div[2]/form/table[1]/tbody/tr[19]/td[2]/input', data['amount'])
    # 年利率
    wd.input('/html/body/div[2]/form/table[1]/tbody/tr[27]/td[2]/input', data['rate'], force=True)
    # 筹标期限
    wd.input('/html/body/div[2]/form/table[1]/tbody/tr[28]/td[2]/input', data['enddate'], force=True)
    # 借款状态
    wd.click('/html/body/div[2]/form/table[1]/tbody/tr[33]/td[2]/label[1]/input')
    # 开始时间
    wd.input('//*[@id="start_time"]', data['start_time'], force=True)
    # 新增提交
    wd.click('/html/body/div[2]/form/table[6]/tbody/tr[2]/td[2]/input[4]')
    # 系统提示
    msg = wd.find_element('/html/body/div/table/tbody/tr[3]/td').text
    assert msg == '添加成功'

2. Excel+关键字驱动

2.1 设计Excel格式

在tests目录新建一个excel表格,内容如下:

其中admin_driver是用例使用的fixture,不同的用例使用id为0来分辨。

2.2 从excel中读取数据

安装openyxl

pip install openpyxl

core目录下新建datas.py封装excel读取的方法

from openpyxl import load_workbook, workbook


def load_case_by_excel(file):
    """从excel中加载用例"""
    wb: workbook = load_workbook(file)  # 打开文件
    # suite_list用来存放所有sheet的名称和对应的用例步骤
    suite_list = []
    for ws in wb.worksheets:
        # case_list用来存放一个sheet中的用例步骤
        case_list = []
        suite = {
            "name": ws.title,
            "case_list": case_list
        }

        suite_list.append(suite)
        for line in ws.iter_rows(values_only=True, min_row=2):  # 逐行读取单元格的值
            # 如果第一个是0,就是用例名称
            if line[0] == 0:
                case = {
                    "name": "",  # 用例名称
                    "steps": []  # 用例步骤
                }
                case_list.append(case)
                case['name'] = line[3]
            # 如果不是0,就是用例步骤
            else:
                case['steps'].append(line)

    return suite_list

2.3 将数据变为pytest识别的用例

        在tests目录下创建test_excel.py,从excel中加载数据,根据数据创建pytest可以识别和执行的用例(test_开头的函数)

from core.datas import load_case_by_excel
from core.cases import create_pytest_case

data= load_case_by_excel("D:\\pythonProject2\\tests\\新建 XLSX 工作表.xlsx")

test_list = create_pytest_case(data)
print(test_list)
# 从列表中取出测试用例,保存为全局变量
i = 0
for _test in test_list:
    i +=1
    globals()[f"test_{i}"] = _test

print(test_list)

2.4 从数据中解析信息并使用keyword

        此处直接将生成allure报告也写了进去,关于allure具体安装方法可以自行百度或者参照我之前在接口自动化的文章。

在core目录下新建cases.py,

import logging
import allure
import pytest

from core.kdt import KeyWord

logger = logging.getLogger()


def handle_name(s):
    try:
        l = s.index("(")
        r = s.index(")")
        case_name = s[:l]
        fixture_name = s[l + 1:r]
        return case_name, fixture_name
    except:
        return s, "driver"


def handle_step(s):
    name = s[1]
    key = s[2]
    args = []
    for arg in s[3:]:
        if arg is not None:
            args.append(arg)
    return name, key, args


def create_pytest_case(suite_list):
    """根据数据,创建pytest可以识别和执行的用例"""
    test_list = []
    for suite in suite_list:
        @allure.feature("web自动化测试平台")
        @allure.story(suite["name"])
        @pytest.mark.parametrize(
            "case",
            suite["case_list"],
            ids=[case["name"] for case in suite["case_list"]],
        )
        def test_abc(case, request):
            logger.info("测试用例开始执行")
            # 根据excel内容,动态调用指定的夹具
            # 拿到用例名称
            case_name = handle_name(case["name"])[0]
            # 拿到夹具名称
            fixture_name = handle_name(case["name"])[1]
            logger.info(f"用例名称:{case_name=},{fixture_name=}")

            driver = request.getfixturevalue(fixture_name)
            kw = KeyWord(driver)  # 实例化keyword
            # 根据excel内容进行关键字调用
            for step in case["steps"]:
                print(step)
                name, key, args = handle_step(step)
                logger.info(f"执行关键字{name=},{key=},{args=}")
                with allure.step(name):
                    func = getattr(kw, key)  # 通过反射拿到关键字执行函数
                    func(*args)  # 调用关键字函数
            logger.info("测试用例结束")
            allure.attach(driver.get_screenshot_as_png(), "添加图片")
        test_list.append(test_abc)

    return test_list

2.5 运行并生成报告

在终端输入 python main.py -k excel -vs来指定运行我们excel测试用例,或者运行main.py

import os

import pytest

if __name__ == '__main__':
    os.environ['NO_COLOR'] = '1'
    pytest.main()
    os.system("allure generate ./temp/allure_results -o report --clean")

可以看到生成了测试报告。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1350344.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

合并数组或对象的几种方法

1.两个数组对象合入一起 const cc [{id: 1,age: 80岁,name: 444,},{id: 1,age: 804岁,name: 2,},{id: 1,age: 803岁,name: 3,},{id: 1,age: 830岁,name: 33,},{id: 1,age: 1022220岁,name: 白龙马111111111,}, ] const reslutList [{id: 1,age: age,name: 唐曾,},{id: 1,age…

windows无命令升级降级node版本

1. node最新版本下载链接 点击最新下载链接,找到对应版本下载并解压 2. 通过命令where node找到node.exe位置 3. 将该位置的node.exe替换为下载解压的最新node.exe 4. 重新执行node -v查看版本 --------------------------------------------------------------…

论文解读:A New CNN Building Block for Low-ResolutionImages and Small Objects

引言 之前通过stride和pooling这些下采样操作,但是这些操作都会或多或少丢失图像的信息,所以这不适用于具有低分辨率图像和小物体的更困难的任务上。像池化选择maxpooling或者是averagepooling、卷积的步长(太大的话会丢失信息)都是很头疼的问题&#x…

QT登录功能开发

登录功能 1选择无按钮的dialog 2登录函数 #include <QApplication> #include <QDialog> #include <QFormLayout> #include <QLineEdit> #include <QPushButton> #include <QMessageBox>class LoginDialog : public QDialog { public:Log…

Axure软件大全:原型设计下载与学习指南!

Axure可以有效地创建原型&#xff0c;包括绘制APP和网页的原型图、框架图、结构图等。Axure内置的小部件可以用来构建动态交互。即使新手设计师不懂程序代码&#xff0c;也可以在Axure中创建复杂、动态、功能丰富的原型。对于想要深入研究和花时间学习程序的设计师来说&#xf…

LeetCode74二分搜索优化:二维矩阵中的高效查找策略

题目描述 力扣地址 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true &#xff1b;否则&…

Android静态代码检查及自定义Lint实现

概述 在日常的项目开发迭代中&#xff0c;相信每个人对与代码质量都是有着高要求的。但是&#xff0c;在所有事情中&#xff0c;人往往就是其中最大的变量因素&#xff0c;个人各异&#xff0c;如何去保障代码质量以及统一规范呢&#xff1f;开发团队也许会严格要求Code-Review…

如何使用Node.js快速创建本地HTTP服务器并实现公网访问服务端

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

抖店新手该如何运营?

我是电商珠珠 在抖店开好之后&#xff0c;大部分新手都不知道怎么去运营&#xff0c;今天&#xff0c;我就来给大家详细的讲一下。 第一步&#xff0c;店铺基础设置 我一直跟我的学生讲&#xff0c;一定要懂基本流程&#xff0c;只有前期将流程跑通了后期才可以毫无压力。 …

css 保持元素宽高比 随页面宽度变化高度自适应

目录 1.效果展示 2.代码内容 3.代码解析 &#xff08;1&#xff09;分析inner类写法 &#xff08;2&#xff09;分析container类写法 1.效果展示 2.代码内容 <div class"item"><div class"inner"><di class"container">…

LED显示屏恒流驱动芯片的功能特点

LED显示屏恒流驱动芯片是一种电子器件&#xff0c;用于控制和驱动LED显示屏。由于LED显示屏通常由大量LED灯珠组成&#xff0c;因此需要使用恒流驱动芯片来确保每个LED灯珠都能够正常、均匀地发光&#xff0c;并且能够控制显示的色彩和亮度。 SM16380SF 恒流驱动芯片通常具有以…

Windows本地如何部署Apache服务器搭配内网穿透实现无公网IP远程访问?

文章目录 前言1.Apache服务安装配置1.1 进入官网下载安装包1.2 Apache服务配置 2.安装cpolar内网穿透2.1 注册cpolar账号2.2 下载cpolar客户端 3. 获取远程桌面公网地址3.1 登录cpolar web ui管理界面3.2 创建公网地址 4. 固定公网地址 前言 Apache作为全球使用较高的Web服务器…

RDS创建数据库

目录 创建数据库 创建账号与授权 连接RDS数据库 创建数据库 在创建数据库的页面&#xff0c;你需要设置数据库的名称、字符集、排序规则等信息。 字符集&#xff1a;字符集&#xff08;Character set&#xff09;是多个字符的集合&#xff0c;字符集种类较多&#xff0c;每个…

前缀和算法 -- [模版]二维前缀和

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 本题链接 【模板】二维前缀和_牛客题霸_牛客网 输入描述 n是行&#xff0c;m是列&#xff0c;q是查询次数&#xff0c;x1&#xff0c;y1&#xff0c;x2&#xff0c;y2是二维数组的下标。 输出描述 通过两对下标&#x…

nginx+keepalived实现七层负载

目录 一、部署nginx01、nginx02 二、keepalived配置&#xff08;抢占模式、master- backup模式&#xff09; 三、测试 四、非抢占模式&#xff08;backup-backup模式&#xff09; nginx01 11.0.1.31nginx0211.0.1.32虚拟IP&#xff08;VIP&#xff09;11.0.1.30 一、部署ngin…

JDBC->SpringJDBC->Mybatis封装JDBC

一、JDBC介绍 Java数据库连接&#xff0c;&#xff08;Java Database Connectivity&#xff0c;简称JDBC&#xff09;是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口&#xff0c;提供了诸如查询和更新数据库中数据的方法。JDBC也是Sun Microsystems的商标。我们…

WPF+Halcon 培训项目实战(8-9):WPF+Halcon初次开发

文章目录 前言相关链接项目专栏运行环境匹配图片WPF Halcon组件HSmartWindowControlWPF绑定读取图片运行代码运行结果 抖动问题解决运行结果 绘制矩形绘制图像会消失 绘制对象绑定事件拖动事件 前言 为了更好地去学习WPFHalcon&#xff0c;我决定去报个班学一下。原因无非是想…

数据结构——顺序栈与链式栈的实现

目录 一、概念 1、栈的定义 2、栈顶 3、栈底 二、接口 1、可写接口 1&#xff09;数据入栈 2&#xff09;数据出栈 3&#xff09;清空栈 2、只读接口 1&#xff09;获取栈顶数据 2&#xff09;获取栈元素个数 3&#xff09;栈的判空 三、栈的基本运算 四、顺序栈&…

【CISSP学习笔记】5. 安全架构和工程

该知识领域涉及如下考点&#xff0c;具体内容分布于如下各个子章节&#xff1a; 使用安全设计原理来研究、实施与管理工程过程理解安全模型的基本概念&#xff08;例如 Biba、Star Model、Bell-LaPadula 等模型&#xff09;基于系统安全要求选择控制措施理解信息系统 (IS) 的安…

智能对话意图分析服务接口

机器人聊天&#xff0c;智能助手&#xff0c;内容生成&#xff0c;智能办公&#xff0c;智能辅助&#xff0c;智能搜索 一、接口介绍 通过接收用户提出的问题、输入的图片和文档等需求&#xff0c;准确识别其对话意图&#xff0c;并触发相应的回复。同时&#xff0c;整合了AP…