笔记:web自动化测试(PO模式)(黑马)

目录

V3版本

v4版本


PO模式学习思路

采用版本迭代的方式来学习,便于对不同版本的优缺点进行对比和理解。

V1:不使用任何设计模式和单元测试框架

V2:使用UnitTest管理用例

V3:使用方法封装的思想,对代码进行优化

V4:采用PO模式的分层思想对代码进行拆分

V5:对PO分层之后的代码继续优化

V6:PO模式深入封装,把共同操作提取封装到父类中,子类直接调用父类的方法

案例说明

对TPshop项目的登录模块进行自动化测试。

提示:登录模块包含了很多测试用例,比如:账号不存在、密码错误、验证码错误、登录成
功等等。
为了节省时间我们只选取几个有代表性的用例来演示。

选择的测试用例

账号不存在
1. 点击首页的‘登录’链接,进入登录页面
2. 输入一个不存在的用户名
3. 输入密码
4. 输入验证码
5. 点击登录按钮
6. 获取错误提示信息
密码错误
1. 点击首页的‘登录’链接,进入登录页面
2. 输入用户名
3. 输入一个错误的密码
4. 输入验证码
5. 点击登录按钮
6. 获取错误提示信息

V1版本

不使用任何设计模式和单元测试框架。 每个文件里编写一个用例,完全的面向过程的编程方式。

V2版本

使用UnitTest管理用例,并断言用例的执行结果(selenium+UnitTest)

不具体讲了(可以看以前的文章)

方法封装

方法封装:是将一些有共性的或多次被使用的代码提取到一个方法中,供其他地方调用。
封装的好处:
    避免代码冗余
    容易维护
    隐藏代码实现的细节
目的:用最少的代码实现最多的功能

V3版本

使用方法封装的思想,对代码进行优化。

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

定义获取驱动对象的工具类

封装“获取弹出框的提示消息”

定义获取驱动对象的工具类

对登录流程的代码进行优化,定义获取驱动对象的工具类

案例:

封装代码:

"""
页面对象层:
    页面对象编写技巧:
        类名:使用大驼峰将模块名称抄进来,有下滑线去掉下划线
        方法:根据业务需求每个操作步骤单独封装一个方法
            方法名 page_XXX

"""
from selenium import webdriver


class PageLogin:
    def __init__(self):
        # 获取driver对象
        self.driver = webdriver.Chrome()
        # 最大化浏览器
        self.driver.maximize_window()
        # 隐式等待
        self.driver.implicitly_wait(30)
        # 打开url
        self.driver.get("https://demo6.tp-shop.cn/")

    # 点击登录 连接
    def page_click_login_link(self):
        self.driver.find_element_by_partial_link_text("登录").click()

    # 输入用户名
    def page_input_username(self, username):
        self.driver.find_element_by_css_selector("#username").send_keys(username)

    # 输入密码
    def page_input_pwd(self, pwd):
        self.driver.find_element_by_css_selector("#password").send_keys(pwd)


    # 输入验证码
    def page_input_verify_code(self, code):
        self.driver.find_element_by_css_selector("#verify_code").send_keys(code)

    # 点击登录按钮
    def page_click_login_btn(self):
        self.driver.find_element_by_css_selector(".J-login-submit").click()

    # 获取异常提示信息
    def page_get_text(self):
        return self.driver.find_element_by_css_selector(".layui-layer-content").text

    # 点击提示框确定按钮
    def page_click_err_btn_ok(self):
        self.driver.find_element_by_css_selector(".layui-layer-btn0").click()

    # 组装登录业务方法  给业务层调用
    def page_login(self, usrename, pwd, code):
        self.page_click_login_link()
        self.page_input_username(usrename)
        self.page_input_pwd(pwd)
        self.page_input_verify_code(code)
        self.page_click_login_btn()

业务代码:

# 导包
import unittest

from parameterized import parameterized

from po实践.v3.page.page_login import PageLogin


# 新建测试类
class TestLogin(unittest.TestCase):
    # 初始化方法
    def setUp(self):
        # 获取登录页面对象
        self.login = PageLogin()

    # 结束方法
    def tearDown(self):
        # 关闭驱动对象
        self.login.driver.quit()

    # 新建测试方法
    @parameterized.expand([("13822223333","123456","8888","账号不存在!"), ("13800001111","123123","8888","密码错误!")])
    def test_login(self, username, pwd, code, expect):
        # 调用测试登录方法
        self.login.page_login(username, pwd, code)
        # 获取登录后的信息
        msg = self.login.page_get_text()
        try:
            # 断言
            self.assertEqual(msg, expect)
            # 点击确定
            self.login.page_click_err_btn_ok()
        except AssertionError:
            # 截图
            pass

PO模式介绍

在做UI自动化时定位元素特别依赖页面,一旦页面发生变更就不得不跟着去修改定位元素的代码。 举例:假设要对一个元素进行点击操作,而且会经常对该元素进行操作,那么你就可能会编写多 处如下代码

driver.find_element_by_id("login-btn").click()

存在的问题:

如果开发人员修改了这个元素的id,这时候你就不得不修改所有对应的代码

存在大量冗余代码

PO模式

PO是Page Object的缩写,PO模式是自动化测试项目开发实践的最佳设计模式之一。

核心思想是通过对界面元素的封装减少冗余代码,同时在后期维护中,若元素定位发生变化, 只 需要调整页面元素封装的代码,提高测试用例的可维护性、可读性。

PO模式可以把一个页面分为三层,对象库层、操作层、业务层。
对象库层:封装定位元素的方法。
操作层:封装对元素的操作。
业务层:将一个或多个操作组合起来完成一个业务功能。比如登录:需要输入帐号、密码、点
击登录三个操作。

拓展:元组解包

from selenium.webdriver.common.by import By
loc = By.CSS_SELECTOR,".telA"

print(type(loc))
print("未解包之前:",loc)
print("解包之后",*loc)

v4版本

v4版本:
		结构:
			1. base(基类):page页面一些公共的方法;
				# Base类
					# 初始化方法
					# 查找元素方法
					# 点击元素方法
					# 输入方法
					# 获取文本方法
					# 截图方法
					注意:
						1. 以上方法封装时候,解包只需1此,在查找元素解包;
						2. driver为虚拟,谁调用base时,谁传入,无需关注从哪里来;
						3. loc:真正使用loc的方法只有查找元素方法使用;
			2. page(页面对象):一个页面封装成一个对象;
				应用:继承base;
				
				实现:
					1. 模块名:page+实际操作模块名称  如:page_login.py 
					2. 页面对象名:以大驼峰方法将模块名抄进来,有下划线去掉下划线
					3. 方法:涉及元素,将每个元素操作单独封装一个操作方法;
					4. 组装:根据需求组装以上操作步骤;
			3. scripts(业务层):导包调用 page页面
				实现: 
					1. 模块:test+实际操作模块名称 如:test_login.py 
					2. 测试业务名称:以大驼峰方法将模块名抄进来,有下划线去掉下划线
					3. 方法: 
						1. 初始化方法 setUp() 注:在unittest框架中不能使用def __init__()初始化方法;
							# 实例化 页面对象 
							# 前置操作 如:打开等等
						2. 结束方法 teardown
							# 关闭驱动
						3. 测试方法
							# 根据要操作的业务来实现

看看文件结构:

从上面可以看出有3层结构

base文件的base.py文件


import time
from selenium import webdriver
# 显式等待
from selenium.webdriver.support.wait import WebDriverWait


class Base:
    # 初始化
    def __init__(self,driver):
        self.driver = driver

#   查找元素方法
    def base_find_lement(self,loc,timeout=30,poll = 0.5):
        """
         :param loc: 元素的配置信息,格式为元组 如:login_link = By.PartialLink, "登录"
         :param timeout: 默认超时时间为30,可以通过传入参数进行修改
         :param poll: 默认访问频率 0.5秒
         :return: 查找到的元素
        """
        return WebDriverWait(self.driver,timeout=timeout,poll_frequency=poll).until(lambda x: x.find_element(*loc))

#     点击方法
    def base_click(self,loc):
        self.base_find_lement(loc).click()
#
#     输入方法
    def base_input(self,loc,value):
        el = self.base_find_lement(loc)
#         清空
        el.clear()
#         输入
        el.send_keys(value)

#     获取文本方法
    def base_get_text(self,loc):
        return self.base_find_lement(loc).text

#     截图方法
    def base_get_image(self):
        self.driver.get_screenshot_as_file("./%s.png"%(time.strftime("%Y_%m_%d %H_%M_%S")))

get_drive.py文件

from selenium import webdriver
from po实践.v4 import page

class GetDriver:

    # 设置类属性
    driver = None

    # 获取driver
    @classmethod
    def get_driver(cls):
        if cls.driver is None:
            # 实例化浏览器
            cls.driver = webdriver.Chrome()
            # 最大化
            cls.driver.maximize_window()
            # 打开浏览器
            cls.driver.get(page.url)
        return cls.driver

    # 退出driver
    @classmethod
    def quit_driver(cls):
        if cls.driver:
            cls.driver.quit()

            # 注意:此处有一个很大坑
            cls.driver = None
            # print("置空之后:", cls.driver)

page文件中的__init__.py文件

from selenium.webdriver.common.by import By
"""以下为服务器域名配置地址"""
url = "https://demo6.tp-shop.cn/"

"""以下为登录页元素配置信息,临时存放地"""
# 登录链接
login_link = By.PARTIAL_LINK_TEXT,"登录"
# 用户名
login_username  = By.ID,"username"
# 密码
login_password  = By.ID,"password"
# 验证码
login_verify_code  = By.ID,"verify_code"
# 点击登录按钮
login_btn  =By.CSS_SELECTOR,".J-login-submit"
# 获取异常文本信息
login_err_info  =By.CSS_SELECTOR,".layui-layer-content"
# 点击异常提示框
login_err_btn_ok  =By.CSS_SELECTOR,".layui-layer-btn0"

page文件中的page_login.py文件


# 获取 浏览器驱动对象
from po实践.v4.base.base import Base
from po实践.v4 import page

class PageLogin(Base):
    # 点击登录链接
    def page_click_login_link(self):
        self.base_click(page.login_link)
    # 输入用户名
    def page_input_username(self,username):
        self.base_input(page.login_username,username)
    # 输入密码
    def page_input_password(self,pwd):
        self.base_input(page.login_password,pwd)
    # 输入验证码
    def page_input_verify_code(self,code):
        self.base_input(page.login_verify_code,code)
    # 点击登录
    def page_click_login_btn(self):
        self.base_click(page.login_btn)
    # 获取异常提示
    def page_get_error_info(self):
        return self.base_get_text(page.login_err_info)
    # 点击异常信息
    def page_click_err_btn_ok(self):
        self.base_click(page.login_err_btn_ok)
    # 截图
    def page_get_ing(self):
        self.base_get_image()
#     组合业务方法
    def page_login(self,username,passwrd,code):
        self.page_input_username(username)
        self.page_input_password(passwrd)
        self.page_input_verify_code(code)
        self.page_click_login_btn()

test_login.py文件

# 导包
import  unittest
from po实践.v4.page.page_login import PageLogin
from parameterized import parameterized
from po实践.v4.base.get_driver import GetDriver

# 获取数据
def get_data():
    return [("13822223333","123456","8888","验证码错误"), ("13800001111","123123","8888","账号不存在!")]



# 新建测试类并继承
class TestLongin(unittest.TestCase):

    # setup
    def setUp(self):
        # 获取driver
        self.driver = GetDriver().get_driver()
        # 初始化 计算页面对象PageLogin
        self.login = PageLogin(self.driver)
    #     点击登录链接
        self.login.page_click_login_link()

    # tearDown
    def tearDown(self):
        # 关闭driver
        GetDriver().quit_driver()
    # 登录测试方法
    @parameterized.expand(get_data())
    def test_login(self,username,pwd,code, expect):
        # 调用登录方法
        self.login.page_login(username,pwd,code)
        # 获取登录提示信息
        msg = self.login.page_get_error_info()
        # 断言
        self.assertEqual(expect,msg)
        # 点击确定
        self.login.page_click_err_btn_ok()

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值