【UI自动化测试】3_PO模式 _封装思想

文章目录

一、封装思想

1、封装类:

  • 获取浏览器驱动对象
  • 关闭浏览器驱动对象

2、封装公用获取元素文本的函数

3、根据文本判断元素是否存在的函数

1.1 认识封装

方法封装:是将一些有共性的或多次被使用的代码提取到一个方法(函数)中,供其他地方调用。

封装作用:

  • 减少部分代码冗余
  • 方便维护
  • 隐藏代码的实现细节

目的: 用最少的代码实现最多的功能

二、代码实现

python 复制代码
version_03:
-__init__.py
- utils.py       (工具类)
- test_login.py   (登录)
- test_address.py (新增地址)

2.1 utils.py

python 复制代码
import logging
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait

# 驱动工具类
class DriverUtils:
    # 初始化私有属性(不希望外部修改值)
    __driver = None

    # 获取浏览器驱动对象
    # 整个测试用例运行过程中会多次调用获取驱动对象的方法,按照实例方法调用的话每次都要创建对象,调用就会出现多个浏览器
    # 整个测试用例运行时,第一次打开浏览器驱动对象,则把浏览器驱动对象存储起来
    # 下次调用获取驱动对象时,判断当前是否有存储的浏览器驱动对象,如有则直接返回,如没有则创建
    @classmethod
    def get_driver(cls):
        """
        1、拷贝一份共性的代码
        2、修改代码的错误
        3、分析封装的代码中是否要参数化数据
        4、分析封装代码的运行结果是否需要返回
        5、优化代码
        :return:驱动对象
        """
        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:
            sleep(2)
            cls.__driver.quit()
            # 将__driver值恢复为None
            cls.__driver = None


# 函数:公用的获取任意元素文本
def get_el_text(xpath_str):
    # 获取元素文本
    # msg = DriverUtils.get_driver().find_element(By.XPATH, xpath_str).text
    # 重要的信息,最好是显示等待
    try:
        msg = WebDriverWait(DriverUtils.get_driver(), 10, 1).until(lambda x:x.find_element(By.XPATH, xpath_str)).text
        print(msg)
    except Exception as e:
        logging.error("没有获取到{xpath_str}的元素对象文本!")
        msg = None
    # 返回获取的文本
    return msg


# 函数:根据文本判断当前页面是否有对应的元素对象
def el_is_exist_by_text(key_text):
    # 根据本次新增的【收货人】信息的文本,到界面上找元素,如果能找到则代表信息成功,找不到则失败截图
    try:
        # 显示等待
        # 如果找到元素对象则把元素对象赋值给is_suc变量
        is_suc = WebDriverWait(DriverUtils.get_driver(), 10, 1).until(lambda x: x.find_element(By.XPATH, f"//*[text()='{key_text}']"))
    except Exception as e:
        # 找不到则给is_suc变量赋值为False
        is_suc = False
        # 截图
        DriverUtils.get_driver().get_screenshot_as_file(f"{key_text}未找到.png")
        logging.error(f"未找到文本为{key_text}的元素对象!")
    # 返回是否找到结果
    return is_suc

2.2 test_login.py

python 复制代码
# 导包
from time import sleep
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By

from version_03.utils import DriverUtils, get_el_text


# 1、定义测试类 --->模块(登录模块)
class TestLogin():

    # 开始执行测试之前只会打开一次浏览器
    def setup_class(self):
        # 类方法的调用:创建对象.方法()
        self.driver = DriverUtils.get_driver()

    # 所有的测试用例都运行完毕才会关闭浏览器
    def teardown_class(self):
        DriverUtils.quit_driver()


    # 每个测试方法的起点一致;那么证明每个测试方法运行之前都会回到首页
    def setup(self):
        self.driver.get("https://hmshop-test.itheima.net/")

    # 2、定义测试方法 ---> 标题
    # 登录失败-(账户不存在)
    def test_login_account_not_exist(self):
        # 4、暂停3s ->代替测试步骤
        # a。使用Xpath 文本定位策略定位登录超链接,并点击
        self.driver.find_element_by_xpath("//*[text()='登录']").click()
        # b。使用Xpath 属性定位策略定位用户名输入框,并输入13600001111
        self.driver.find_element_by_xpath("//*[@id='username']").send_keys("13611111111")
        # c。使用Xpath  属性包含定位策略定位密码输入框,并输入123456
        self.driver.find_element_by_xpath("//*[contains(@id,'pass')]").send_keys("123456")
        # d。使用Xpath  属性与逻辑结合策略定位验证码输入框,并输入8888
        self.driver.find_element_by_xpath('//*[@placeholder="验证码" and @id="verify_code"]').send_keys("8888")
        # e。使用Xpath 层级与属性结合策略定位登录按钮,并点击;
        self.driver.find_element_by_xpath("//*[@class='login_bnt']/a").click()
        sleep(2)
        # 获取实际结果:
        msg = get_el_text("//*[@class='layui-layer-content layui-layer-padding']")
        # 判断实际结果和预期结果是否一致
        assert msg == "账号不存在!"


    # 登录失败-(密码错误)
    def test_login_password_error(self):
        # 4、暂停3s ->代替测试步骤
        # a。使用Xpath 文本定位策略定位登录超链接,并点击
        self.driver.find_element_by_xpath("//*[text()='登录']").click()
        # b。使用Xpath 属性定位策略定位用户名输入框,并输入13600001111
        self.driver.find_element_by_xpath("//*[@id='username']").send_keys("13600001111")
        # c。使用Xpath  属性包含定位策略定位密码输入框,并输入123456
        self.driver.find_element_by_xpath("//*[contains(@id,'pass')]").send_keys("error")
        # d。使用Xpath  属性与逻辑结合策略定位验证码输入框,并输入8888
        self.driver.find_element_by_xpath('//*[@placeholder="验证码" and @id="verify_code"]').send_keys("8888")
        # e。使用Xpath 层级与属性结合策略定位登录按钮,并点击;
        self.driver.find_element_by_xpath("//*[@class='login_bnt']/a").click()
        sleep(2)
        # 获取实际结果
        msg = get_el_text("//*[@class='layui-layer-content layui-layer-padding']")
        # 断言,期望的提示信息包含在实际结果中
        assert "密码错误" in msg


2.3 test_address.py

python 复制代码
# 导包
import time
from time import sleep
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.wait import WebDriverWait

from version_03.utils import el_is_exist_by_text, DriverUtils


class TestAddress:
    # 开始执行测试之前只会打开一次浏览器
    def setup_class(self):
        self.driver = DriverUtils.get_driver()
        self.driver.get("https://hmshop-test.itheima.net/")



    # 所有的测试用例都运行完毕才会关闭浏览器
    def teardown_class(self):
        DriverUtils.quit_driver()


    def test_01_login_suc(self):
        # a。使用Xpath 文本定位策略定位登录超链接,并点击
        self.driver.find_element_by_xpath("//*[text()='登录']").click()
        # b。使用Xpath 属性定位策略定位用户名输入框,并输入13600001111
        self.driver.find_element_by_xpath("//*[@id='username']").send_keys("13600001111")
        # c。使用Xpath  属性包含定位策略定位密码输入框,并输入123456
        self.driver.find_element_by_xpath("//*[contains(@id,'pass')]").send_keys("123456")
        # d。使用Xpath  属性与逻辑结合策略定位验证码输入框,并输入8888
        self.driver.find_element_by_xpath('//*[@placeholder="验证码" and @id="verify_code"]').send_keys("8888")
        # e。使用Xpath 层级与属性结合策略定位登录按钮,并点击;
        self.driver.find_element_by_xpath("//*[@class='login_bnt']/a").click()
        sleep(2)

    def test_02_add_address(self):
        # 2、在个人中心页面点击【账户设置】下【收货地址】
        ActionChains(self.driver).move_to_element(self.driver.find_element(By.XPATH, "//*[text()='账户设置']")).perform()
        self.driver.find_element(By.XPATH, "//*[text()='收货地址']").click()
        """
        # (*)获取当前已经保存地址条数
        old_num = self.driver.find_elements(By.CSS_SELECTOR, "em.red")[0].text
        print(f"新增地址前,已保存的地址条数为{old_num}")
        """

        # 3、点击【新增地址】:收货人信息 = cus{当前时间}
        self.driver.find_element(By.XPATH, "//*[text()='增加新地址']").click()

        customer_name = f"cus{time.strftime('%H_%M_%S')}"
        # 4、完成新增地址操作
        self.driver.find_element(By.CSS_SELECTOR, '[name="consignee"]').send_keys(customer_name)
        self.driver.find_element(By.CSS_SELECTOR, '[name="mobile"]').send_keys("13600001112")

        Select(self.driver.find_element(By.ID, "province")).select_by_value("1")  # value属性值为1,代表北京
        Select(self.driver.find_element(By.ID, "city")).select_by_value("2")     # 市辖区2
        Select(self.driver.find_element(By.ID, "district")).select_by_value("39")  # 朝阳区39
        Select(self.driver.find_element(By.ID, "twon")).select_by_value("40")  # 建外街道40

        self.driver.find_element(By.CSS_SELECTOR, '[name="address"]').send_keys("幸福门街道26栋")
        self.driver.find_element(By.CSS_SELECTOR, '[name="zipcode"]').send_keys("100000")

        self.driver.find_element(By.ID, "address_submit").click()
        # 当UI自动化脚本操作功能时,如该步骤会自动触发发送请求,最好在触发之后跟上强制等待1秒,防止发送请求失败
        sleep(1)

        """
        # 5、控制滚动条移动到页面最底部
        js_str = "window.scrollTo(0,2000)"
        self.driver.execute_script(js_str)
        sleep(2)
        # 6、刷新下界面
        self.driver.refresh()
        # (*)再次获取当前已经保存地址条数
        new_num = self.driver.find_elements(By.CSS_SELECTOR, "em.red")[0].text
        print(f"新增地址前,已保存的地址条数为{new_num}")
        # (*)判断新增完后的地址条数是否+1 如果+1则打印新增成功,否则打印新增失败
        if int(new_num) -1 == int(old_num):
            print("新增成功")
        else:
            print("新增失败")
        """
        # 根据本次新增的【收货人】信息的文本,到界面上找元素,如果能找到则代表信息成功,找不到则失败截图

        assert el_is_exist_by_text(customer_name)
相关推荐
lntu_ling5 小时前
Python-基于Haversine公式计算两点距离
开发语言·python·gis算法
哈里谢顿11 小时前
Django 应用 OOM(Out of Memory)故障的定位思路和排查方法
python·django
甄心爱学习11 小时前
【python】获取所有长度为 k 的二进制字符串
python·算法
左手厨刀右手茼蒿12 小时前
Flutter for OpenHarmony: Flutter 三方库 image_size_getter 零加载极速获取图片尺寸(鸿蒙 UI 布局优化必备)
android·服务器·flutter·ui·华为·harmonyos
钛态12 小时前
Flutter for OpenHarmony:dio_cookie_manager 让 Dio 发挥会话管理能力,像浏览器一样自动处理 Cookie 深度解析与鸿蒙适配指南
android·linux·运维·flutter·ui·华为·harmonyos
tuotali202612 小时前
氢气压缩机技术规范亲测案例分享
人工智能·python
嫂子的姐夫12 小时前
030-扣代码:湖北图书馆登录
爬虫·python·逆向
a11177613 小时前
EasyVtuber(或其衍生/增强版本)的虚拟主播(Vtuber)面部动画生成与直播解决方案
python·虚拟主播
lintax13 小时前
计算pi值-积分法
python·算法·计算π·积分法