5

Selenium4+Python3系列(十) - Page Object设计模式 - 久曲健

 1 year ago
source link: https://www.cnblogs.com/longronglang/p/16930414.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Page Object(PO)模式,是Selenium实战中最为流行,并且被自动化测试同学所熟悉和推崇的一种设计模式之一。在设计测试时,把页面元素定位和元素操作方法按照页面抽象出来,分离成一定的对象,然后再进行组织。

相信每个做自动化测试的同学,一定会遇到这样一个非常头疼的问题,那就是页面变化,如果没有使用Page Object设计模式,这就意味着以前的定位元素方法不能用了,需要重新修改元素定位方式。你需要一个一个从测试脚本中把需要修改的元素定位方式找出来,然后再进行修改。这势必会使脚本维护的成本变高,显然这样的自动化脚本就不会有人愿意使用。

那这时我们使用Page Object模式就可以解决这个问题了。

PageObject 的优点

  • 减少代码冗余
  • 业务和实现分离
  • 降低代码维护成本

Page Object模式

Page Object 见名知意,就是页面对象,并将页面元素定位方法和元素操作进行分离。

在实际自动化测试实战过程中,我们一般对脚本的实现分为三层:

  • 对象层:用于存放页面元素定位和控件操作。
  • 逻辑层:则是一些封装好的功能用例模块。
  • 业务层:则是我们真正的测试用例的操作部分。

使用 Page Object 类来分离页面元素

首先我们新建一个类login_page,登录页面内编写需要操作的元素定位方式和控件操作,具体代码示例如下:

python
# -*- coding: utf-8 -*-
"""
# @Time    : 2022/11/26 22:16
# @Author  : longrong.lang
# @FileName: login_page.py
# @Software: PyCharm
# @Blog    :https://www.cnblogs.com/longronglang/
# @Motto:ABC(Always Be Coding)
"""
import time

from selenium.webdriver.common.by import By


class LoginPage:
    """
    封装元素定位及控件
    """

    def __int__(self, driver):
        self.driver = driver

    # 打开浏览器
    def open(self, url):
        self.driver.get(url)

    # 用户名元素定位
    def user_name(self):
        return self.driver.find_element(By.CSS_SELECTOR, "input[type='text']")

    # 密码元素定位
    def pass_word(self):
        return self.driver.find_element(By.CSS_SELECTOR, "input[type='password']")

    # 登录元素定位
    def login_btn(self):
        return self.driver.find_element(By.CSS_SELECTOR, "button[name='submit']")

    # 错误提示
    def error_msg(self):
        return self.driver.find_element(By.ID, "alert")

    # 输入用户名
    def send_username(self, username):
        self.user_name().clear()
        self.user_name().send_keys(username)

    # 输入密码
    def send_password(self, password):
        self.pass_word().clear()
        self.pass_word().send_keys(password)

    # 点击登录
    def click_login(self):
        self.login_btn().click()

    # 获取错误提示
    def get_errorMsg(self):
        time.sleep(1)
        return self.error_msg().text

    # 退出浏览器
    def quit(self):
        self.driver.quit()

这里我只对用户名和密码输入框进行了封装,有兴趣的同学也可以接着进行全部元素操作封装。

我们再新建一个类login_action,用于登录逻辑的封装,供业务层调用,具体代码示例如下:

python
# -*- coding: utf-8 -*-
"""
# @Time    : 2022/11/26 22:33
# @Author  : longrong.lang
# @FileName: login_action.py
# @Software: PyCharm
# @Blog    :https://www.cnblogs.com/longronglang/
# @Motto:ABC(Always Be Coding)
"""
import time

from pageobject.login_page import LoginPage


class LoginAction(LoginPage):

    def login(self, username, password, expected):
        self.open("http://localhost:8080/login")
        self.send_username(username)
        self.send_password(password)
        self.click_login()
        time.sleep(1)
        msg = self.get_errorMsg()
        assert msg == expected
        self.quit()

最后我们新建一个类test_login,用于业务层的封装,具体代码示例如下:

python
# -*- coding: utf-8 -*-
"""
# @Time    : 2022/11/26 22:43
# @Author  : longrong.lang
# @FileName: test_login.py
# @Software: PyCharm
# @Blog    :https://www.cnblogs.com/longronglang/
# @Motto:ABC(Always Be Coding)
"""
from pageobject.login_action import LoginAction
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager


class TestLogin(LoginAction):
    def test_login(self):
        self.driver = webdriver.Chrome(ChromeDriverManager().install())
        self.driver.maximize_window()
        self.driver.implicitly_wait(5)
        self.login("username", "pwd", "登录失败!")

虽然该实现方法看上去复杂多了,但其中的设计好处是不同层关心不同的问题。页面对象只关心元素的定位,测试用例只关心测试数据。

login_page类中主要对登录页面上元素进行封装,使其成为具体的操作方法。如对用户名、密码框都封装成方法,然后定义login(self, username, password, expected)方法将单个元素操作组成一个完整的动作,包含输入用户名、密码并点击登录按钮等。

使用时将driver、username、pwd、expected作为函数的入参,这样的方法具有很强的可重用性。

最后使用test_login()方法进行用户操作行为,现在只关心用哪个浏览器、登录的用户名和密码是什么,至少输入框、按钮是如何定位的,则不关心。即实现了不同层关心不同问题。如果再有定位元素变化,只需login_page这个类维护即可,显然方便了很多。

__EOF__


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK