UI自动化测试实战

news2024/11/18 23:30:31

目录

  • 1 自动化测试流程
  • 2 项目介绍
    • 2.1 项目功能和技术
    • 2.2 项目简介
    • 2.3 用例设计
    • 2.4 编写代码
      • 2.4.1 公共方法
      • 2.4.2 抽取PO
    • 2.5 视频

1 自动化测试流程

步骤:

  1. 需求分析
  2. 挑选适合做自动化测试的功能【人力不足时,选择冒烟测试】
  3. 设计并筛选测试用例
  4. 搭建自动化测试环境
  5. 设计自动化测试项目的架构
  6. 编写代码
  7. 执行测试用例
  8. 生成测试报告并分析结果

在这里插入图片描述

2 项目介绍

2.1 项目功能和技术

  1. 业务特性
  2. 用户和角色
  3. 功能模块
  4. 技术栈

2.2 项目简介

项目名称
TPShop开源商城系统
项目描述
TPShop是一个电子商务B2C电商平台系统,功能强大安全便捷。适合企业及个人快速构建个性化网上商城

包含PC+IOS客户端+Android客户端+微商城,系统PC+后台是基于ThinkPHP MVC构架开发的跨平台开源软件设计得非常灵活,具有模块化架构体系和丰富的功能,易于与第三方应用系统无缝集成,在设计上,包含相当全面,以模块化架构体系,让应用组合变得相当灵活,功能也相当丰富

项目架构
Windows + PHP + Apache + MySQL

2.3 用例设计

编写规则

  1. 自动化测试用例一般只实现核心业务流程或者重复率较高功能
  2. 自动化测试用例的选择一般以“正向”逻辑的验证为主
  3. 不是所有手工测试用例都可以使用自动化测试
  4. 尽量减少多个用例脚本之间的依赖
  5. 自动化测试执行用例完毕后,一般需要回归原点

在这里插入图片描述

2.4 编写代码

2.4.1 公共方法

base.action.py

class BaseAction:
    # 初始化驱动
    def __init__(self, driver):
        self.driver = driver

    # 查找单个元素
    def find_el(self, feature):
        return self.driver.find_element(*feature)

    # 查找多个元素
    def find_els(self, feature):
        return self.driver.find_elements(*feature)

    # 查找按钮元素
    def click(self, feature):
        return self.find_el(feature).click()

    # 查找输入元素
    def input(self, feature, content):
        return self.find_el(feature).send_keys(content)

    # 清空
    def clear(self, feature):
        return self.find_el(feature).clear()

    # 定位数字按钮
    def find_el_num(self, feature, num):
        return self.driver.find_element(feature[0], feature[1].format(str(num)))

    # 切换指定的页面
    def switch_to(self, frame_feature):
        return self.driver.switch_to.frame(self.find_el(frame_feature))

    # 切换回默认页面
    def switch_to_default(self):
        return self.driver.switch_to_default_content()

    # 切换新窗口
    def switch_windows(self):
        handles = self.driver.window_handles()
        return self.driver.switch_to(handles[-1])

driver_utils.py

# 获取/关闭浏览器驱动的类
from selenium import webdriver


class DriverUtils:
    __driver = None
    __switch = True

    # 获取浏览器驱动
    @classmethod
    def get_driver(cls):
        if cls.__driver is None:
            cls.__driver = webdriver.Chrome()
            cls.__driver.maximize_window()
            cls.__driver.implicitly_wait(10)
        return cls.__driver

    # 关闭浏览器驱动
    @classmethod
    def quit_driver(cls):
        if cls.__driver is not None and cls.__switch is False:
            cls.__driver.quit()
            cls.__driver = None

    # 设置浏览器开关
    @classmethod
    def set_switch(cls, switch):
            cls.__switch = switch

read_data.py

# 读取data数据文件
import json


def read_data(filename):
    with open("./data/" + filename, "r", encoding="utf-8") as f:
        list_data = []
        dict_list = json.load(f)
        for value in dict_list.values():
            list_data.append(value)
        return list_data

2.4.2 抽取PO

1. 定义页面对象

首页:index_page.py

# 首页
from selenium.webdriver.common.by import By

from base.base_action import BaseAction


class IndexPage(BaseAction):
    # 登录链接
    login_link_btn = By.CLASS_NAME, "red"
    # 搜索框
    search_input = By.ID, "q"
    # 搜索 按钮
    search_btn = By.CLASS_NAME, "ecsc-search-button"
    # 购物车 链接
    my_cart_link = By.CLASS_NAME, "c-n"
    # 我的订单 链接
    my_order_link = By.XPATH, "/html/body/div[1]/div[1]/div/ul/li[1]/a"

    # 点击首页的"登录"链接, 进入登录页面
    def click_login_link(self):
        return self.click(self.login_link_btn)

    # 输入关键字,进行搜索商品
    def input_keywords(self, content):
        return self.input(self.search_input, content)

    # 点击搜索按钮
    def click_search_btn(self):
        return self.click(self.search_btn)

    # 点击"我的订单"链接
    def click_my_order_link(self):
        return self.click(self.my_order_link)

    # 点击"我的购物车"链接
    def click_my_cart_link(self):
        return self.click(self.my_cart_link)

登录页:login_page.py

# 登录页面
from selenium.webdriver.common.by import By
from base.base_action import BaseAction


class LoginPage(BaseAction):
    # 登录链接 按钮
    login_link_btn = By.CLASS_NAME, "red"
    # 用户名 输入框
    username_input = By.ID, "username"
    # 密码 输入框
    password_input = By.ID, "password"
    # 验证码 输入框
    verify_code_input = By.ID, "verify_code"
    # 登录 按钮
    login_btn = By.NAME, "sbtbutton"

    # 点击首页的"登录"链接, 进入登录页面
    def click_login_link(self):
        return self.click(self.login_link_btn)

    # 输入用户名
    def input_username(self, content):
        return self.input(self.username_input, content)

    # 输入密码
    def input_password(self, content):
        return self.input(self.password_input, content)

    # 输入验证码
    def input_verify_code(self, content):
        return self.input(self.verify_code_input, content)

    # 点击登录按钮
    def click_login_btn(self):
        return self.click(self.login_btn)

个人中心页:home_page.py (登录成功之后会跳转到该页面)

# 个人中心页面
from selenium.webdriver.common.by import By

from base.base_action import BaseAction


class HomePage(BaseAction):
    # 立即支付 按钮
    pay_btn = By.CLASS_NAME, "ps_lj"
    # 待付款标签
    pend_pay = By.XPATH, "//*[text()='待付款']"

    # 点击立即付款按钮
    def click_immed_pay_btn(self):
        return self.click(self.pay_btn)

    # 点击付款链接
    def click_pay_btn(self):
        return self.click(self.pend_pay)

商品搜索页:goods_search_page.py(搜索商品之后的页面,即搜索后的列表)

# 商品搜索页面
from selenium.webdriver.common.by import By
from base.base_action import BaseAction


class GoodsSearchPage(BaseAction):
    # 加入购物车
    add_cart_btn = By.XPATH, "/html/body/div[4]/div/div[2]/div[2]/ul/li[1]/div/div[5]/div[2]/a"

    # 点击加入购物车按钮
    def click_add_cart_btn(self):
        return self.click(self.add_cart_btn)

商品详情页:goods_detail_page.py

# 商品详情页面
from selenium.webdriver.common.by import By
from base.base_action import BaseAction


class GoodsDetailPage(BaseAction):
    # 加入购物车
    details_add_cart_btn = By.CSS_SELECTOR, ".addcar"

    # iframe
    cart_iframe = By.CSS_SELECTOR, "[id*='layui-layer-iframe']]"

    # 加入购物车成提示语
    result_msg = By.CSS_SELECTOR, "#addCartBox > div.colect-top > div > span"

    # 点击加入购物车 按钮
    def click_details_add_cart_btn(self):
        return self.click(self.details_add_cart_btn)

    # 获取弹窗框的结果
    def get_result(self):
        # 切换到iframe中,再获取结果
        self.switch_to(self.cart_iframe)
        return self.find_el(self.result_msg).text

购物车页:cart_page.py

# 购物车页面
from selenium.webdriver.common.by import By
from base.base_action import BaseAction


class CartPage(BaseAction):
    # 结算按钮
    go_to_btn = By.CLASS_NAME, "gwc-qjs"

    # 点击结算按钮
    def click_go_to_btn(self):
        return self.click(self.go_to_btn)

下订单页:order_page.py

# 下订单页面
from selenium.webdriver.common.by import By
from base.base_action import BaseAction


class OrderPage(BaseAction):
    # 提交订单按钮
    submit_btn = By.CLASS_NAME, "Sub-orders"

    # 点击提交订单按钮
    def click_submitr_btn(self):
        return self.click(self.submit_btn)

订单支付页:order_pay_page.py

# 订单支付页面
from selenium.webdriver.common.by import By
from base.base_action import BaseAction


class OrderPayPage(BaseAction):
    # 订单状态信息
    tips_info = By.XPATH, "/html/body/div[2]/div/div[2]/div[1]/h3"
    # 货到付款选择
    arrived_pay = By.XPATH, "//input[@value='pay_code=cod']"
    # 确认支付方式 按钮
    pay_btn = By.CLASS_NAME, "button-confirm-payment"

    # 获取订单状态信息
    def click_tips_info(self):
        return self.find_el(self.tips_info).text

    # 点击货到付款选框
    def click_arrived_pay(self):
        return self.click(self.arrived_pay)

    # 确认支付方式 按钮
    def click_pay_btn(self):
        return self.click(self.pay_btn)

总结: 首先根据测试流程,简写出每一步关键词(流程),根据页面再写出属性和方法

2. 编写测试脚本

登录模块:test_login.py

# 导包
import json
import time
import pytest
from page.index_page import IndexPage
from page.login_page import LoginPage
from utils.driver_utils import DriverUtils
from utils.read_data import read_data


# 定义测试类
class TestLogin:

    def setup_method(self):
        self.driver = DriverUtils.get_driver()
        DriverUtils.set_switch(True)
        self.login_page = LoginPage(self.driver)
        self.index_page = IndexPage(self.driver)
        self.driver.get("http://192.168.157.137")

    def teardown_method(self):
        time.sleep(5)
        DriverUtils.quit_driver()

    @pytest.mark.parametrize("params", read_data("login_data.json"))
    def test_login(self, params):
        # 1. 点击首页的"登录"链接, 进入登录页面
        self.index_page.click_login_link()
        # 2. 输入用户名
        self.login_page.input_username(params["username"])
        # 3. 输入一个错误密码
        self.login_page.input_password(params["password"])
        # 4. 输入验证码
        self.login_page.input_verify_code(params["code"])
        # 5. 点击登录按钮
        self.login_page.click_login_btn()
        # 暂停5秒,等待跳转
        time.sleep(5)
        # 断言,判断页面的title,是否一致
        assert params["msg"] in self.driver.title

购物车模块:test_cart.py

import logging
import time
import pytest

from page.cart_page import CartPage
from page.goods_detail_page import GoodsDetailPage
from page.goods_search_page import GoodsSearchPage
from page.index_page import IndexPage
from utils.driver_utils import DriverUtils
from utils.read_data import read_data


class TestCart:
    def setup_method(self):
        self.driver = DriverUtils.get_driver()
        self.index_page = IndexPage(self.driver)
        self.goods_search_page = GoodsSearchPage(self.driver)
        self.goods_detail_page = GoodsDetailPage(self.driver)
        self.driver.get("http://192.168.157.137")

    def teardown_method(self):
        time.sleep(5)
        DriverUtils.quit_driver()

    @pytest.mark.parametrize("params", read_data("cart_data.json"))
    def test_search_to_cart(self, params):
        # 1. 点击首页搜索框输入关键字
        self.index_page.input_keywords(params["keywords"])
        # 2. 点击搜索按钮
        self.index_page.click_search_btn()
        logging.info("search XiaoMiPhone")
        # 3. 点击搜索列表“加入购物车”按钮
        self.goods_search_page.click_add_cart_btn()
        # 4. 在商品详情页面,点击添加购物车
        self.goods_detail_page.click_details_add_cart_btn()
        # 等待弹窗,5秒之后
        time.sleep(5)
        logging.info("wait 5s for the page to display")
        # 断言,查看是否"添加成功"字样
        assert params["msg"] == self.goods_detail_page.get_result()	

订单模块:testt_order.py

import logging
import time
import pytest

from page.cart_page import CartPage
from page.home_page import HomePage
from page.index_page import IndexPage
from page.order_page import OrderPage
from page.order_pay_page import OrderPayPage
from utils.driver_utils import DriverUtils
from utils.read_data import read_data


class TestOrder:
    def setup_method(self):
        self.driver = DriverUtils.get_driver()
        self.index_page = IndexPage(self.driver)
        self.order_page = OrderPage(self.driver)
        self.order_pay_page = OrderPayPage(self.driver)
        self.cart_page = CartPage(self.driver)
        self.home_page = HomePage(self.driver)
        self.driver.get("http://192.168.157.137")

    def teardown_method(self):
        time.sleep(5)
        self.driver.get_screenshot_as_file("./screenshot/tpshop.png")
        DriverUtils.quit_driver()

    @pytest.mark.parametrize("params", read_data("order_data.json"))
    def test_submit_order(self, params):
        # 1. 首页点击"我的购物车"
        self.index_page.click_my_cart_link()
        # 2. 点击去结算
        self.cart_page.click_go_to_btn()
        logging.info("go settle")
        # 等待5秒
        time.sleep(5)
        logging.info("wait 5s for the page to display")
        # 1. 点击提交订单按钮
        self.order_page.click_submitr_btn()
        logging.info("submit order")
        # 断言,判断状态信息是否正确
        assert params["msg"] == self.order_pay_page.click_tips_info()

    @pytest.mark.parametrize("params", read_data("pay_data.json"))
    def test_pay(self, params):
        # 1. 点击"我的订单"
        self.index_page.click_my_order_link()
        time.sleep(5)
        # 2. 在个人中心点击”待付款“
        self.home_page.click_immed_pay_btn()
        time.sleep(5)
        # 3. 点击立即支付按钮
        self.home_page.click_pay_btn()
        time.sleep(5)
        # 4. 点击选择货到付款
        self.order_pay_page.click_arrived_pay()
        # 5. 点击确认支付方式按钮
        self.order_pay_page.click_pay_btn()
        logging.info("Confirm payment")
        time.sleep(5)
        logging.info("wait 5s for the page to display")
        # 断言 状态
        assert params["msg"] == self.order_pay_page.click_tips_info()

注意: 建议每个功能模块对应一个py文件

3. 日志配置类

import logging.handlers


def set_log_config():
    # 创建日志器对象
    logger = logging.getLogger()
    # 设置日志器级别
    logger.setLevel(level=logging.DEBUG)
    # 创建处理器对象 输出到控制台
    ls = logging.StreamHandler()
    lf = logging.handlers.TimedRotatingFileHandler(filename="./log/tshop.log", when="d", backupCount=3)
    # 创建格式器对象
    fmt = "%(asctime)s %(levelname)s [%(name)s] [%(filename)s:%(funcName)s:%(lineno)d] - %(message)s"
    formartter = logging.Formatter(fmt=fmt)
    # 将格式器添加到处理器
    ls.setFormatter(formartter)
    lf.setFormatter(formartter)
    # 将处理器添加到日志器
    logger.addHandler(ls)
    logger.addHandler(lf)

2.5 视频

在这里插入图片描述

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

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

相关文章

JMemter镜像下载地址

腾讯软件源: https://mirrors.cloud.tencent.com/ JMemter镜像下载地址: https://mirrors.cloud.tencent.com/apache/jmeter https://mirrors.cloud.tencent.com/apache/jmeter/binaries

信创服务器操作系统的适配迁移分析

浅谈信创服务器操作系统的适配迁移 01 服务器操作系统迁移适配流程复杂 随着CentOS停服临近和红帽RHEL源码权限受限,服务器操作系统安全漏洞风险加剧。国内众多企业面临CentOS、REHL等系统升级替换的挑战。同时,出于安全、功能升级和合规需求&#xff0…

企业数据资产入表操作指引

在数字经济时代,数据已成为企业的关键生产要素,其管理和应用至关重要。数据资产入表操作涉及复杂的评估和管理过程,企业需要遵循合规性、真实性和透明性的原则。本指南旨在为企业提供系统化的操作指导,帮助实现数据资产的高效管理…

ARM32开发-fat_fs文件系统

FAT_FS 文件系统 FAT (File Allocation Table) 文件系统是一种广泛使用的基于磁盘的文件系统,尤其适用于小型嵌入式系统和存储卡。FAT_FS 就是一个专门针对 FAT 文件系统的开源实现。 FAT_FS 的主要特点 轻量级和高度可移植: FAT_FS 是一个非常轻量级的文件系统实现,占用资源少…

【JS重点15】原型对象概述

目录 一:构造函数缺陷 二:原型 1 原型是是什么 2 原型对象的作用 3 原型对象this指向问题 4 利用原型对象添加方法 给JS内置构造函数Array添加最大值方法 给JS内置构造函数Array添加求和方法 三:Constructor属性 四:如何…

应用无感,透明加密!麒麟信安商用密码改造方案助力密改合规

数字信息化时代,在产业政策与市场驱动的共同作用下,密码产品和应用服务需求日趋旺盛,合规、正确、有效地使用密码,是数据安全防护体系中的有效手段。但当前,各行各业信息系统中国产密码算法应用不合规、未使用、使用不…

使用Python实现自动化查询IP威胁情报

解决的问题 一名网络安全从业人员在做日常网络安全运营分析时,就从防火墙、IDP、WAF等安全设备的日志分析计算,基本都会面对成千上万条日志,好一点的可能会有态势感知之类安全产品提供辅助分析,如果没有的就只能单条进行分析&…

彻底卸载Ubuntu双系统

操作系统 文章目录 操作系统前言一、把开机启动项设为默认Windows启动二、删除Ubuntu系统分区三、删除开机启动引导项 前言 我们卸载Ubuntu双系统,可能出于以下原因: 1、Ubuntu系统内核损坏无法正常进入 2、Ubuntu系统分配空间不足,直接扩区…

如何规范信息技术课堂纪律

在信息技术课堂上,为了营造一个良好的学习环境,确保学生能够专注于学习任务,我们需要采取一系列措施来规范课堂纪律。以下是一些具体而详细的建议: 一、明确课堂规则 上课座位固定:学生的座位应固定,未经…

分享一个dnslog在线平台

DNSLog Platform 页面只有两个按钮,点击Get Subdomain可以随机生成一个dnslog 点击Refresh Record,刷新这个dnslog的记录。可以查看到这条dnslog的IP地址和创建时间。

vue elementui table给表格中满足条件的每一条记录添加计时器

需求: 在前端给表格中给满足条件的每一条记录增加一个计时器,用于计算工作时长。 1.数据库中存储的有每条记录的作业开始时间,将当前时间和作业开始时间计算一个差值,作为作业时长的初始值; 2.把满足条件的每条记录绑…

为什么很多Java程序员会下意识觉得Java的就是最好的?

在开始前刚好我有一些资料,是我根据网友给的问题精心整理了一份「Java的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!!做为一个真正热爱编程&#…

信捷PLC与上位机通讯-以太网通讯dll

应用场景 最近做项目,电气部分PLC选用了国产的信捷PLC,需要考虑上位机与信捷PLC通讯的问题,直接读写寄存器或线圈。 解决方案 信捷官网找资料,介绍的各种通讯方法,感觉都不是很好理解,而且也没办法直接拿…

二刷算法训练营Day27 (Day26 休息) | 回溯算法(3/6)

目录 详细布置: 1. 39. 组合总和 2. 40. 组合总和 II 3. 131. 分割回文串 详细布置: 1. 39. 组合总和 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同…

【数据结构】线性表之《无头单链表》超详细实现

单链表 一.链表的概念及结构二.顺序表与链表的区别与联系三.单链表的实现1.创建单链表2.初始化单链表3.购买节点4.打印单链表5.插入操作1.头插2.尾插3.给定位置之前插入 6.删除操作1.头删2.尾删3.删除给定位置的结点 7.查找数据8.修改数据9.求单链表长度10.清空单链表11.销毁单…

python代码

# 请在______处使用一行代码或表达式替换# 注意:请不要修改其他已给出代码s input("请输入一个字符串:") print("{:*^30}".format(s))# 请在______处使用一行代码或表达式替换 # # 注意:请不要修改其他已给出代码a, b 0, 1 while …

程序员们,能告诉我你们为什么选择arch linux吗?

在开始前刚好我有一些资料,是我根据网友给的问题精心整理了一份「linux的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!! Arch Linux 受到程序员青…

Qt|海康摄像头多个页面展示问题

为大家分享一个使用海康摄像头的小功能,希望对大家有用~ 使用场景: 在程序中多个不同功能页面需要展示摄像头的实时预览画面,该如何高效的展示呢? 对于海康摄像头的实时预览接口调用流程,如下所示: 按照流…

GD32F4xx 移植agile_modbus软件包与电能表通信

目录 1. agile_modbus1.1 简介1.2 下载2. agile_modbus使用2.1 源码目录2.2 移植3. 通信调试3.1 代码3.3 通信测试1. agile_modbus 1.1 简介 agile_modbus是一个轻量级的Modbus协议栈,主要特点: 支持RTU和TCP协议,采用纯C语言开发,不涉及任何硬件接口,可直接在任何形式的…

Java学习 (一) 环境安装及入门程序

一、安装java环境 1、获取软件包 https://www.oracle.com/java/technologies/downloads/ .exe 文件一路装过去就行,最好别装c盘 ,我这里演示的时候是云主机只有C盘 2、配置环境变量 我的电脑--右键属性--高级系统设置--环境变量 在环境变量中添加如下配…