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

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

1. 关键字驱动

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

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

python 复制代码
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中新建测试用例,

python 复制代码
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

python 复制代码
pip install openpyxl

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

python 复制代码
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_开头的函数)

python 复制代码
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

python 复制代码
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

python 复制代码
import os

import pytest

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

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

相关推荐
Mr.D学长16 分钟前
毕业设计 深度学习社交距离检测系统(源码+论文)
python·毕业设计·毕设
wdxylb20 分钟前
解决Python使用Selenium 时遇到网页 <body> 划不动的问题
python
代码骑士28 分钟前
【一起学NLP】Chapter3-使用神经网络解决问题
python·神经网络·自然语言处理
wxin_VXbishe1 小时前
springboot合肥师范学院实习实训管理系统-计算机毕业设计源码31290
java·spring boot·python·spring·servlet·django·php
ITenderL1 小时前
Python学习笔记-函数
python·学习笔记
zmjia1111 小时前
全流程Python编程、机器学习与深度学习实践技术应用
python·深度学习·机器学习
_.Switch2 小时前
Python机器学习:自然语言处理、计算机视觉与强化学习
python·机器学习·计算机视觉·自然语言处理·架构·tensorflow·scikit-learn
JUNAI_Strive_ving2 小时前
番茄小说逆向爬取
javascript·python
彤银浦2 小时前
python学习记录7
python·学习
简单.is.good3 小时前
【测试】接口测试与接口自动化
开发语言·python