Python&Selenium、UI自动化测试之PO设计模式——QQ邮箱举例

面向对象的特性:封装、继承、多态。在自动化中一样适用,Selenium自动化测试中有一个名字常常被提及PageObject(思想与面向对象的特性相同),通过PO模式可以大大提高测试用例的维护效率。

##传统测试脚本的弊端

测试脚本分离,维护成本高
可扩展性差
复用性低等
PageObject设计模式
selenium自动化测试框架之PO设计模式

PO的核心要素:

在PO模式中抽象封装成一个BasePage类,该基类应该拥有一个只实现webdriver实例的属性。
每个一个page都继承BasePage,通过driver来管理本page中元素,将page中的操作封装成一个个的方法。
TestCase继承unittest.Testcase类,并且依赖page类,从而实现相应的测试步骤。·

案例
基础案例
前面基础场景选取的是QQ邮箱、写信操作!

公共方法类—封装公用的操作方法

class DriverUtil(object):
"""定义浏览器工具类"""

_driver = None

# 添加自动退出标记
_auto_quit = True

@classmethod
def get_driver(cls):
    """获取浏览器对象方法"""
    if cls._driver is None:
        # 初始化浏览器对象
        cls._driver = webdriver.Chrome()
        # 设置窗口最大化
        cls._driver.maximize_window()
        # 设置隐式等待
        cls._driver.implicitly_wait(10)
        # 打开链接
        cls._driver.get('https://mail.qq.com/')
    return cls._driver

@classmethod
def quit_driver(cls):
    """退出浏览器对象方法"""
    if cls._auto_quit and cls._driver:
        cls._driver.quit()
        cls._driver = None

@classmethod
def auto_quit(cls, auto_quit):
    """开关浏览器退出方法"""
    cls._auto_quit = auto_quit

分析

将获取的驱动对象都封装到一个类中,有要使用时,调用当前文件就可。

页面元素属性类—存取所有需要使用的元素

from selenium.webdriver.common.by import By


class UIElements:
"""管理所有页面元素"""

"""qq邮箱登陆页面"""

Account_password_login_btn = (By.ID, 'switcher_plogin')  # 账号密码登陆按钮

input_user_name = (By.ID, 'u')  # 账号输入框

input_password = (By.ID, 'p')  # 密码输入框

login_button = (By.ID, 'login_button')  # 登录按钮

"""qq邮箱首页"""

write_a_letter_btn = (By.XPATH, '//*[@id="composebtn"]')  # 写信按钮

inbox_btn = (By.ID, 'folder_1')  # 收件箱按钮

"""写信页面"""

Recipient_input_box = (By.XPATH, "//*[@id='toAreaCtrl']/div[2]/input")  # 收件人输入框

Subject_input_box = (By.ID, 'subject')  # 主题输入框

text_input = (By.XPATH, '/html/body')  # 正文输入框

send_btn = (By.XPATH, '//*[@id="toolbar"]/div/a[1]')  # 发送按钮

Return_homepage = (By.ID, 'btnbackl')  # 返回邮箱首页按钮

"""收件箱页面"""

apple_email = (
    By.XPATH, '//*[@id="div_showlastweek"]/table[1]/tbody/tr/td[3]/table/tbody/tr/td[1]/nobr/span')  # 具体邮件
user_email = (
    By.XPATH, '//*[@id="mailContentContainer"]/table/tbody/tr/td/div[1]/table/tbody/tr[4]/td/table/tbody/tr[1]/td/table/tbody/tr[1]/td[1]/a') #页面邮箱号元素

分析

所有页面需要用到的元素定位属性,放到一起方便管控,要使用时调用此类即可,如页面元素修改,及只要修改此页面元素的属性值即可。

Base操作类—封装主要的操作方法

from utils import DriverUtil


class Base(object):
"""page操作类"""

def __init__(self):
    self.driver = DriverUtil.get_driver()

def get_element(self, loc):
    """
    单个元素定位(利用拆包获取元组属性值)
    :param loc: 元素对象定位方法类型和属性值
    :return: 元素对象
    """
    return self.driver.find_element(*loc)

def get_elements(self, loc):
    """
    定位一组元素
    :param loc: (By.ID,id属性值) (By.CLASS_NAME,class属性值) (By.XPATH,xpath属性值)
    :return:元素定位对象列表
    """
    return self.driver.find_elements(*loc)

def click_element(self, loc):
    """
    点击元素
    :param loc: (By.ID,id属性值) (By.CLASS_NAME,class属性值) (By.XPATH,xpath属性值)
    :return:
    """
    self.get_element(loc).click()

def send_element(self, loc, text):
    """
    输入文本内容
    :param loc: (By.ID,id属性值) (By.CLASS_NAME,class属性值) (By.XPATH,xpath属性值)
    :param text: 输入文本内容
    :return:
    """
    # 定位元素
    input_text = self.get_element(loc)
    # 清空输入框
    input_text.clear()
    # 输入元素
    input_text.send_keys(text)

def get_text_information(self, loc):
    """
    获取当前元素的文本信息
    :param loc: (By.ID,id属性值) (By.CLASS_NAME,class属性值) (By.XPATH,xpath属性值)
    :return:
    """
    return self.get_element(loc).text

分析

此类中为操作事件方法,现已有的点击、输入、获取改元素上的文本信息,可结合自身使用,自主添加各种方法。(需要使用方法时调用此类即可)

page类—实现页面每一步操作

"""qq邮箱登陆页面"""
from base.base import Base
from page.UIElements import UIElements
import json
import config
import logging

class EmailLoginPage(Base):

def __init__(self):
    super().__init__()

def account_password_login(self):
    """点击账号密码登陆"""
    self.click_element(UIElements.Account_password_login_btn)

def input_username(self, username):
    """输入用户名"""
    self.send_element(UIElements.input_user_name, username)

def input_password(self, pwd):
    """输入密码"""
    self.send_element(UIElements.input_password, pwd)

def click_login_btn(self):
    """点击登陆按钮"""
    self.click_element(UIElements.login_button)

分析

页面类,把每个页面分开,每个页面写入需操作的方法,按页面分(这边举例的是登陆页面上的所有操作方法和步骤)

脚本类—将页面类所有操作步骤按顺序执行

class TestLogin(unittest.TestCase):

@classmethod
 def setUpClass(cls):
    cls.driver = DriverUtil.get_driver()  # 获取浏览器驱动对象
    cls.email_login_page = EmailLoginPage()  # 获取登陆页驱动对象

    cls.driver.switch_to.frame("login_frame") # 切换至输入框窗口
    cls.email_login_page.account_password_login()  # 点击使用账号密码登陆

@classmethod
def tearDownClass(cls):
    DriverUtil.quit_driver()  # 退出浏览器


def tearDown(self):
    time.sleep(3)


def test_login(self ):
    self.email_login_page.input_username(“aaaa”)  # 输入用户名

    self.email_login_page.input_password("11111")  # 输入密码

    self.email_login_page.click_login_btn()  # 点击登陆

    # 设置睡眠,等待页面标题的加载
    time.sleep(2)
    # 获取页面标题
    title = self.driver.title

    # 断言判断测试结果
    self.assertIn("断言结果", title)

分析

脚本类,执行上述页面的方法,在此处运行脚本

在编写测试用例testcase的代码,主要是测试用例执行的功能,可以按照场景编写每个用例,也可以实现之前讲述的数据分离驱动测试数据。来进行各种读取和调用,通过unittest 框架来执行测试用例继承unittest.TestCase
后面会使用HTMLTestRunner 生成测试报告,邮件发送及PO设计模式的测试框架
————————————————

你可能感兴趣的:(软件测试)