Python —— UI自动化之Page Object模式

1、Page Object模式简介

1、二层模型

Page Object Model(页面对象模型), 或者也可称之为POM。在UI自动化测试广泛使用的一种分层设计 模式。核心是通过页面层封装所有的页面元素及操作,测试用例层通过调用页面层操作组装业务逻辑。

1、实战

目录如下:

home_page.py文件的内容:

python 复制代码
from selenium.webdriver.common.by import By

class HomePage:
    login_link_locator = (By.LINK_TEXT, '登录')

    def click_login_link(self,driver):
        # 前面加*号是解包的操作,因为login_link_locator是元组
        driver.find_element(*self.login_link_locator).click()

login_page.py文件的内容:

python 复制代码
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import By


class LoginPage:
    #属性->元素定位信息(元素定位方法+元素定位值)-元组类型
    phone_input_locator = (By.XPATH,'//input[@placeholder="请输入手机号/用户名"]')
    pwd_input_locator = (By.XPATH,'//input[@placeholder="请输入密码"]')
    login_button_locator = (By.CLASS_NAME,'login-button')

    #操作->元素行为,登录操作
    def page_login(self,driver,phone,pwd):
        # *self.phone_input_locator 前面的*号是解包使用的
        driver.find_element(*self.phone_input_locator).send_keys(phone)
        driver.find_element(*self.pwd_input_locator).send_keys(pwd)
        sleep(2)
        driver.find_element(*self.login_button_locator).click()

登录案例 - PO.py的文件内容:

python 复制代码
from selenium import webdriver
from d6_JavaScript处理.testcases.home_page import HomePage
from d6_JavaScript处理.testcases.login_page import LoginPage

driver = webdriver.Chrome()
driver.maximize_window()
driver.get("http://mall.banan.com:3344/")
HomePage().click_login_link(driver)

LoginPage().page_login(driver,"1723693766728","ydgcdlcb")

2、三层模型

基本的PO分层包括页面层与用例层,但是在编写页面层代码时会发现一个问题:页面中存在非常多相同 的操作方法,比如都需要等待元素、获取元素属性/文本信息、页面滚动等等,每个页面层类都需要有相 同的代码,代码存在非常多冗余。我们可以把这些**【公共】**的页面操作方法给提取出来放到一个类中进 行维护,其他的页面类共用该类中的操作方法即可(通过继承实现)。

UI自动化断言:
断言是自动化测试不可缺少的部分,当我们使用测试脚本对业务逻辑进行操作时,需要检查交互操作之 后结果的正确性,此时需要通过断言机制来进行验证。

Pytest测试框架内置丰富的断言,通过assert语句即可,常见的断言方法比较包括:

  • 比较相等
python 复制代码
assert a == b
  • 比较大小(大于/小于/大于等于/小于等于)
python 复制代码
assert a > b
  • 内容包含/内容不包含
python 复制代码
assert a in b
  • 验证表达式是否为真
python 复制代码
assert condition
UI自动化常见的断言条件包括:
  • 通过当前页面的URL地址

  • 通过当前页面的标题

  • 通过当前页面的提示文本信息

  • 通过当前页面的某些元素变化/显示

一句话总结:通过肉眼观察页面的变化检查

3、三层模型实战

思路:抽取一个公共类,这个类中可以写公共页面的属性和函数,也可以写每次都要使用的属性,从UI自动化的角度来看,浏览器驱动是每次执行用例都会用到的,所以也可以抽取出来。

三层模型的文件目录如下:

base_page.py文件中的内容:

python 复制代码
import os

from selenium.webdriver import ActionChains
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

# BasePage 用来存放所有页面类的公共部分,一些公共的操作(显式封装)
class BasePage:
    def __init__(self,driver):
        self.driver = driver

    # 封装的意思:把相同类似的代码放到一个函数里面,重复使用
    # locator是元组的类型
    def wait_element_clickable(self, locator):
        web_element = WebDriverWait(self.driver,5,0.5).until(EC.element_to_be_clickable(locator))
        return web_element

    def wait_element_visible(self, locator):
        # web_element代表通过显示等待找到的元素
        web_element = WebDriverWait(self.driver,5,0.5).until(EC.visibility_of_element_located(locator))
        return web_element

    def wait_element_presence(self, locator):
        web_element = WebDriverWait(self.driver,5,0.5).until(EC.presence_of_all_elements_located(locator))
        return web_element

    # JavaScript进行元素的滚动
    def page_scroll(self,distance):
        self.driver.execute_script(f"document.documentElement.scrollTop={distance}")

    # JavaScript进行元素的点击
    def page_js_click(self,locator):
        element = self.wait_element_visible(self.driver,locator)
        self.driver.execute_script("arguments[0].click()",element)

    # JavaScript进行元素的移除
    def remove_element_attribute(self,locator,attribute):
        element = self.wait_element_visible(self.driver,locator)
        self.driver.execute_script(f"arguments[0].removeAttribute({attribute})", element)

    # 鼠标点击
    def mouse_click(self,locator):
        element = self.wait_element_visible(self.driver,locator)
        ActionChains(self.driver).click(element).perform()

    # 窗口切换
    def switch_to_window(self,title):
        handles = self.driver.window_handles
        for handle in handles:
            if self.driver.title == title:
                break
            else:
                self.driver.switch_to.window(handle)

    # 文件上传
    def update_file(self,filepath):
        os.system(f"test.exe {filepath}")

home_page.py文件中的内容:

python 复制代码
import time

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from PO模式优化与自动化用例断言.common.base_page import BasePage


class HomePage(BasePage):
    # 属性-登录链接
    login_link_locator = (By.LINK_TEXT,'登录')
    # 欢迎提示信息
    welcome_tips_locator = (By.XPATH,'//span[text()="欢迎来到天使的世界"]')
    welcome_tips_text_locator = (By.XPATH,'//span[@class="text"]')
    # 用户名
    username_text_locator = (By.XPATH,'//a[@class="link-name"]')

    def click_login_link(self):
        self.wait_element_clickable(self.login_link_locator).click()

    def is_display_welcome_tips(self):
        time.sleep(2)
        # return  self.wait_element_clickable(self.welcome_tips_locator).is_displayed()
        return self.wait_element_clickable(self.welcome_tips_text_locator).text

    def get_username_text(self):
        return self.wait_element_visible(self.username_text_locator).text

login_page.py文件中的内容:

python 复制代码
import time

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from PO模式优化与自动化用例断言.common.base_page import BasePage


class LoginPage(BasePage):
    # 属性->元素定位信息(元素定位方法+元素定位值)-元组类型
    phone_input_locator = (By.XPATH, '//input[@placeholder="请输入手机号/用户名"]')
    pwd_input_locator = (By.XPATH, '//input[@placeholder="请输入密码"]')
    login_button_locator = (By.CLASS_NAME, 'login-button')
    login_tips_locator = (By.XPATH, '//p[@class="el-message__content"]')

    def login(self,phone,pwd):
        # 因为继承了 basepage类,所以克不用再写driver参数
        # self.wait_element_visible(self.driver,self.phone_input_locator).send_keys("17728373518")
        self.wait_element_visible(self.phone_input_locator).send_keys(phone)
        self.wait_element_visible(self.pwd_input_locator).send_keys(pwd)
        self.wait_element_clickable(self.login_button_locator).click()
        time.sleep(3)

    def get_login_tips(self):
        # 这里比较文本内容
        return self.wait_element_visible(self.login_tips_locator).text
        print(self.wait_element_visible(self.login_tips_locator).text)

test_login.py文件中的内容

python 复制代码
from selenium import webdriver
from d7_PO模式优化与自动化用例断言.pageobjects.home_page import HomePage
from d7_PO模式优化与自动化用例断言.pageobjects.login_page import LoginPage

def test_login_success():
    driver = webdriver.Chrome()
    driver.get("http://mall.banan.com:3344/")
    driver.maximize_window()
    # 点击首页的登录操作
    homepage = HomePage(driver)
    homepage.click_login_link()
    # 在登陆页面进行登录操作
    loginpage = LoginPage(driver)
    loginpage.login("le_auto","le123456")
    # 断言检测测试是否成功(通过预期结果和实际结果的比较)
    #  检查点:1、欢迎页,如果函数的返回值为True,那么断言之后返回是通过的
    assert homepage.is_display_welcome_tips()
    # assert loginpage.get_login_tips() == '账号或者密码不正确'
    assert homepage.get_username_text() == 'lemon_auto'


# 对登录结果的断言
def test_login_uncorrect_username():
    driver = webdriver.Chrome()
    driver.get("http://mall.banan.com:3344/")
    homepage = HomePage(driver)
    homepage.click_login_link()
    # 在登陆页面进行登录操作
    loginpage = LoginPage(driver)
    loginpage.login("le_auto1", "le123456")
    # 页面登录过程中的提示信息断言
    assert loginpage.get_login_tips() == '账号或密码不正确'

2、PO模式的优点

1、提高测试用例的可读性

2、提高测试用例可维护性

3、减少代码重复

相关推荐
愚润求学1 小时前
【Linux】进程间通信(一):认识管道
linux·运维·服务器·开发语言·c++·笔记
SHUIPING_YANG1 小时前
Nginx 返回 504 状态码表示 网关超时(Gateway Timeout)原因排查
运维·nginx·gateway
光不度AoKaNa1 小时前
计算机操作系统概要
linux·运维·服务器
晚秋大魔王1 小时前
OpenHarmony 开源鸿蒙南向开发——linux下使用make交叉编译第三方库——wget
java·linux·运维·开发语言·华为·harmonyos
孤的心了不冷2 小时前
【Linux】Linux安装并配置MongoDB
linux·运维·mongodb·容器
南棱笑笑生2 小时前
20250517让NanoPi NEO core开发板在Ubuntu core16.04.2下支持TF卡的热插拔
linux·运维·ubuntu
jinlei20093 小时前
配置ssh服务-ubuntu到Windows拷贝文件方法
运维·ubuntu·ssh
magic 2453 小时前
第6章:文件权限
linux·运维·服务器
c6lala3 小时前
数据结构day3
linux·运维·服务器
snpgroupcn4 小时前
天能股份SAP系统整合实战:如何用8个月实现零业务中断的集团化管理升级
运维·系统架构