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

发布时间:2024年01月02日

? ? ? ? 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")

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

文章来源:https://blog.csdn.net/weixin_42833736/article/details/135267821
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。