UI自动化测试实战

目录

  • [1 自动化测试流程](#1 自动化测试流程)
  • [2 项目介绍](#2 项目介绍)
    • [2.1 项目功能和技术](#2.1 项目功能和技术)
    • [2.2 项目简介](#2.2 项目简介)
    • [2.3 用例设计](#2.3 用例设计)
    • [2.4 编写代码](#2.4 编写代码)
      • [2.4.1 公共方法](#2.4.1 公共方法)
      • [2.4.2 抽取PO](#2.4.2 抽取PO)
    • [2.5 视频](#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

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

python 复制代码
# 获取/关闭浏览器驱动的类
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

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

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

python 复制代码
# 登录页面
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 (登录成功之后会跳转到该页面)

python 复制代码
# 个人中心页面
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(搜索商品之后的页面,即搜索后的列表)

python 复制代码
# 商品搜索页面
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

python 复制代码
# 商品详情页面
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

python 复制代码
# 购物车页面
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

python 复制代码
# 下订单页面
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

python 复制代码
# 订单支付页面
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

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

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

python 复制代码
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. 日志配置类

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

相关推荐
极梦网络无忧4 小时前
OpenClaw 基础使用说明(中文版)
python
codeJinger4 小时前
【Python】操作Excel文件
python·excel
XLYcmy4 小时前
一个针对医疗RAG系统的数据窃取攻击工具
python·网络安全·ai·llm·agent·rag·ai安全
Islucas5 小时前
Claude code入门保姆级教程
python·bash·claude
萝卜白菜。5 小时前
TongWeb7.0相同的类指明加载顺序
开发语言·python·pycharm
赵钰老师5 小时前
【ADCIRC】基于“python+”潮汐、风驱动循环、风暴潮等海洋水动力模拟实践技术应用
python·信息可视化·数据分析
爬山算法5 小时前
MongoDB(80)如何在MongoDB中使用多文档事务?
数据库·python·mongodb
YuanDaima20486 小时前
基于 LangChain 1.0 的检索增强生成(RAG)实战
人工智能·笔记·python·langchain·个人开发·langgraph
RopenYuan7 小时前
FastAPI -API Router的应用
前端·网络·python