Web自动化测试04

Table of Contents
Web 自动化测试课程
4 -PO 模式
无模式
方法封装
PO 模式介绍
PO 模式实践
PO 模式深入封装
Web 自动化测试课程
序号
章节
知识点
1
第一章 Web 自动化入门
1. 认识自动化及自动化测试
2. 自动化测试工具选择
3. 环境搭建
2
第二章 Selenium-API 操作
1. 元素定位方式
2. 元素和浏览器的操作方法
3. 鼠标和键盘操作
4. 元素等待
5. HTML 特殊元素处理
6. 窗口截图
7. 验证码处理
3
第三章 UnitTest 框架
1. UnitTest 基本使用
2. UnitTest 断言
3. 参数化
4. 生成 HTML 测试报告
4
第四章 PO 模式
1. 方法封装
2. PO 模式介绍
3. PO 模式实战
5
第五章 数据驱动
1. JSON 读写
2. 数据驱动介绍
3. 数据驱动实战
6
第六章 日志收集
1. 日志相关概念
2. 日志的基本方法
3. 日志的高级方法
7
第七章 项目实战
1. 自动化测试流程
2. 项目实战演练
课程目标
1.
掌握使用 Selenium 进行 Web 自动化测试的流程和方法,并且能够完成自动化测试脚本的编
写。
2.
掌握如何通过 UnitTest 管理用例脚本,并生成 HTML 测试报告。
3.
掌握使用 PO 模式来设计自动化测试代码的架构。
4.
掌握使用数据驱动来实现自动化测试代码和测试数据的分离。
5.
掌握使用 logging 来实现日志的收集。
4 -PO 模式
目标
1. 深入理解方法封装的思想
2. 能够使用方法封装的思想对代码进行优化
3. 深入理解 PO 模式的思想
4. 熟练掌握 PO 模式的分层思想
PO 模式学习思路
采用版本迭代的方式来学习,便于对不同版本的优缺点进行对比和理解。
V1 :不使用任何设计模式和单元测试框架
V2 :使用 UnitTest 管理用例
V3 :使用方法封装的思想,对代码进行优化
V4 :采用 PO 模式的分层思想对代码进行拆分
V5 :对 PO 分层之后的代码继续优化
V6 PO 模式深入封装,把共同操作提取封装到父类中,子类直接调用父类的方法
无模式
目标
1. 熟悉 web 自动化测试代码编写的基本流程
2. 掌握如何使用 UnitTest 管理测试脚本
1. 案例说明
TPshop 项目的登录模块进行自动化测试。
提示:登录模块包含了很多测试用例,比如:账号不存在、密码错误、验证码错误、登录成
功等等。
为了节省时间我们只选取几个有代表性的用例来演示。
1.1 选择的测试用例
账号不存在
1.
点击首页的 登录 链接,进入登录页面
2.
输入一个不存在的用户名
3.
输入密码
4.
输入验证码
5.
点击登录按钮
6.
获取错误提示信息
密码错误
1.
点击首页的 登录 链接,进入登录页面
2.
输入用户名
3.
输入一个错误的密码
4.
输入验证码
5.
点击登录按钮
6.
获取错误提示信息
2. V1 版本
不使用任何设计模式和单元测试框架。
每个文件里编写一个用例,完全的面向过程的编程方式。
2.1 存在的问题
一条测试用例对应一个文件,用例较多时不方便管理维护
代码高度冗余
2.2 示例代码
登录功能 - 账号不存在
from selenium import webdriver
# 创建浏览器驱动对象,并完成初始化操作
driver = webdriver.Firefox()
driver.maximize_window()
driver.implicitly_wait( 10 )
driver.get( "http://localhost" )
"""
登录功能 - 账号不存在
"""
# 点击首页的 登录 链接,进入登录页面
driver.find_element_by_link_text( " 登录 " ).click()
# 输入用户名
driver.find_element_by_id( "username" ).send_keys( "13099999999" )
# 输入密码
driver.find_element_by_id( "password" ).send_keys( "123456" )
# 输入验证码
driver.find_element_by_id( "verify_code" ).send_keys( "8888" )
# 点击 登录 按钮
driver.find_element_by_name( "sbtbutton" ).click()
# 获取提示信息
msg = driver.find_element_by_class_name( "layui-layer-content" ).text
print( "msg=" , msg)
# 关闭驱动对象
driver.quit()
登录功能 - 密码错误
from selenium import webdriver
# 创建浏览器驱动对象,并完成初始化操作
driver = webdriver.Firefox()
driver.maximize_window()
driver.implicitly_wait( 10 )
driver.get( "http://localhost" )
"""
登录功能 - 密码错误
"""
# 点击首页的 登录 链接,进入登录页面
driver.find_element_by_link_text( " 登录 " ).click()
# 输入用户名
driver.find_element_by_id( "username" ).send_keys( "13012345678" )
# 输入密码
driver.find_element_by_id( "password" ).send_keys( "error" )
# 输入验证码
driver.find_element_by_id( "verify_code" ).send_keys( "8888" )
# 点击 登录 按钮
driver.find_element_by_name( "sbtbutton" ).click()
# 获取提示信息
msg = driver.find_element_by_class_name( "layui-layer-content" ).text
print( "msg=" , msg)
# 关闭驱动对象
driver.quit()
3. V2 版本
使用 UnitTest 管理用例,并断言用例的执行结果
3.1 引入 UnitTest 的好处
方便组织、管理多个测试用例
提供了丰富的断言方法
方便生成测试报告
减少了代码冗余
3.2 存在的问题
代码冗余
3.3 示例代码
import unittest
from selenium import webdriver
class TestLogin (unittest.TestCase) :
"""
对登录模块的功能进行测试
"""
@classmethod
def setUpClass (cls) :
cls.driver = webdriver.Firefox()
cls.driver.maximize_window()
cls.driver.implicitly_wait( 10 )
cls.driver.get( "http://localhost" )
@classmethod
def tearDownClass (cls) :
cls.driver.quit()
def setUp (self) :
# 打开首页
self.driver.get( "http://localhost" )
# 点击首页的 登录 链接,进入登录页面
self.driver.find_element_by_link_text( " 登录 " ).click()
# 账号不存在
def test_login_username_is_error (self) :
# 输入用户名
self.driver.find_element_by_id( "username" ).send_keys( "13099999999" )
# 输入密码
self.driver.find_element_by_id( "password" ).send_keys( "123456" )
# 输入验证码
self.driver.find_element_by_id( "verify_code" ).send_keys( "8888" )
# 点击 登录
self.driver.find_element_by_name( "sbtbutton" ).click()
# 断言提示信息
msg = self.driver.find_element_by_class_name( "layui-layer-content" ).text
print( "msg=" , msg)
self.assertIn( " 账号不存在 " , msg)
# 密码错误
7
黑马程序员-软件测试
传智播客 www.itcast.cn def test_login_password_is_error (self) :
# 输入用户名
self.driver.find_element_by_id( "username" ).send_keys( "13012345678" )
# 输入密码
self.driver.find_element_by_id( "password" ).send_keys( "error" )
# 输入验证码
self.driver.find_element_by_id( "verify_code" ).send_keys( "8888" )
# 点击 登录
self.driver.find_element_by_name( "sbtbutton" ).click()
# 断言提示信息
msg = self.driver.find_element_by_class_name( "layui-layer-content" ).text
print( "msg=" , msg)
self.assertIn( " 密码错误 " , msg)
方法封装
目标
1. 深入理解方法封装的思想
2. 能够使用方法封装的思想对代码进行优化
1. 方法封装
方法封装:是将一些有共性的或多次被使用的代码提取到一个方法中,供其他地方调用。
封装的好处:
避免代码冗余
容易维护
隐藏代码实现的细节
目的:用最少的代码实现最多的功能
2. V3 版本
使用方法封装的思想,对代码进行优化。
定义获取驱动对象的工具类
封装 获取弹出框的提示消息
2.1 定义获取驱动对象的工具类
对登录流程的代码进行优化,定义获取驱动对象的工具类
# utils.py
class DriverUtil :
"""
浏览器驱动工具类
"""
_driver = None
@classmethod
9
黑马程序员-软件测试
传智播客 www.itcast.cn def get_driver (cls) :
"""
获取浏览器驱动对象,并完成初始化设置
:return: 浏览器驱动对象
"""
if cls._driver is None :
cls._driver = webdriver.Firefox()
cls._driver.maximize_window()
cls._driver.implicitly_wait( 10 )
cls._driver.get( "http://localhost" )
return cls._driver
@classmethod
def quit_driver (cls) :
"""
关闭浏览器驱动
"""
if cls._driver:
cls._driver.quit()
cls._driver = None
2.2 封装 获取弹出框的提示消息
对登录流程的代码进行优化,封装 获取弹出框的提示消息 的方法
# utils.py
def get_tips_msg () :
"""
获取弹出框的提示消息
:return: 消息文本内容
"""
msg = DriverUtil.get_driver().find_element_by_class_name( "layui-layer-content" ).text
return msg
PO 模式介绍
目标
1. 深入理解 PO 模式的思想
2. 熟练掌握 PO 模式的分层思想
1. 存在的问题
在做 UI 自动化时定位元素特别依赖页面,一旦页面发生变更就不得不跟着去修改定位元素的代码。
举例:假设要对一个元素进行点击操作,而且会经常对该元素进行操作,那么你就可能会编写多
处如下代码
driver.find_element_by_id( "login-btn" ).click()
存在的问题:
如果开发人员修改了这个元素的 id ,这时候你就不得不修改所有对应的代码
存在大量冗余代码
思考:如何来解决这个问题呢?
2. PO 模式
PO Page Object 的缩写, PO 模式是自动化测试项目开发实践的最佳设计模式之一。
核心思想是通过对界面元素的封装减少冗余代码,同时在后期维护中,若元素定位发生变化, 只
需要调整页面元素封装的代码,提高测试用例的可维护性、可读性。
PO 模式可以把一个页面分为三层,对象库层、操作层、业务层。
对象库层:封装定位元素的方法。
操作层:封装对元素的操作。
业务层:将一个或多个操作组合起来完成一个业务功能。比如登录:需要输入帐号、密码、点
击登录三个操作。
2.1 引入 PO 模式的好处
引入 PO 模式前
存在大量冗余代码
业务流程不清晰
后期维护成本大
引入 PO 模式后
减少冗余代码
业务代码和测试代码被分开,降低耦合性
维护成本低
PO 模式实践
目标
1. 能够采用 PO 模式的分层思想对页面进行封装
1. V4 版本
采用 PO 模式的分层思想对代码进行拆分
1.1 PO 分层封装
对登录页面进行分层封装:
对象库层: LoginPage
操作层: LoginHandle
业务层: LoginProxy
调用业务层的方法,编写测试用例:
测试用例: TestLogin
1.2 示例代码
from po.utils import DriverUtil
class LoginPage :
"""
对象库层
"""
def __init__ (self) :
self.driver = DriverUtil.get_driver()
# 用户名输入框
self.username = None
# 密码
self.password = None
# 验证码输入框
self.verify_code = None
# 登录按钮
self.login_btn = None
# 忘记密码
self.forget_pwd = None
def find_username (self) :
return self.driver.find_element_by_id( "username" )
def find_password (self) :
return self.driver.find_element_by_id( "password" )
def find_verify_code (self) :
return self.driver.find_element_by_id( "verify_code" )
def find_login_btn (self) :
return self.driver.find_element_by_name( "sbtbutton" )
def find_forget_pwd (self) :
return self.driver.find_element_by_partial_link_text( " 忘记密码 " )
class LoginHandle :
"""
操作层
"""
def __init__ (self) :
self.login_page = LoginPage()
def input_username (self, username) :
self.login_page.find_username().send_keys(username)
def input_password (self, pwd) :
self.login_page.find_password().send_keys(pwd)
def input_verify_code (self, code) :
self.login_page.find_verify_code().send_keys(code)
def click_login_btn (self) :
self.login_page.find_login_btn().click()
def click_forget_pwd (self) :
self.login_page.find_forget_pwd().click()
class LoginProxy :
"""
业务层
"""
def __init__ (self) :
self.login_handle = LoginHandle()
# 登录
def login (self, username, password, verify_code) :
# 输入用户名
self.login_handle.input_username(username)
# 输入密码
self.login_handle.input_password(password)
# 输入验证码
self.login_handle.input_verify_code(verify_code)
# 点击登录按钮
self.login_handle.click_login_btn()
# 跳转到忘记密码页面
def to_forget_pwd_page (self) :
# 点击忘记密码
self.login_handle.click_forget_pwd()
import unittest
from po import utils
from po.utils import DriverUtil
from po.v4.page.login_page import LoginProxy
class TestLogin (unittest.TestCase) :
"""
对登录模块的功能进行测试
"""
@classmethod
def setUpClass (cls) :
cls.driver = DriverUtil.get_driver()
cls.login_proxy = LoginProxy()
@classmethod
def tearDownClass (cls) :
DriverUtil.quit_driver()
def setUp (self) :
# 打开首页
self.driver.get( "http://localhost" )
# 点击首页的 登录 链接,进入登录页面
self.driver.find_element_by_link_text( " 登录 " ).click()
# 账号不存在
def test_login_username_is_error (self) :
self.login_proxy.login( "13099999999" , "123456" , "8888" )
# 断言提示信息
msg = utils.get_tips_msg()
print( "msg=" , msg)
self.assertIn( " 账号不存在 " , msg)
# 密码错误
def test_login_password_is_error (self) :
self.login_proxy.login( "13012345678" , "123456" , "8888" )
# 断言提示信息
msg = utils.get_tips_msg()
print( "msg=" , msg)
self.assertIn( " 密码错误 " , msg)
2. V5 版本
PO 分层之后的代码继续优化
1.
优化对象库层的代码,抽取元素的定位方式,把定位信息定义在对象的属性中,便于集中管理
2.
优化操作层的代码,针对输入操作应该先清空输入框中的内容再输入新的内容
from selenium.webdriver.common.by import By
from po.utils import DriverUtil
class LoginPage :
"""
对象库层
"""
def __init__ (self) :
self.driver = DriverUtil.get_driver()
# 用户名
self.username = (By.ID, "username" )
# 密码
self.password = (By.ID, "password" )
# 验证码输入框
self.verify_code = (By.ID, "verify_code" )
# 登录按钮
self.login_btn = (By.NAME, "sbtbutton" )
# 忘记密码
self.forget_pwd = (By.PARTIAL_LINK_TEXT, " 忘记密码 " )
def find_username (self) :
return self.driver.find_element(self.username[ 0 ], self.username[ 1 ])
def find_password (self) :
return self.driver.find_element(self.password[ 0 ], self.password[ 1 ])
def find_verify_code (self) :
return self.driver.find_element(self.verify_code[ 0 ], self.verify_code[ 1 ])
def find_login_btn (self) :
return self.driver.find_element(self.login_btn[ 0 ], self.login_btn[ 1 ])
def find_forget_pwd (self) :
return self.driver.find_element(self.forget_pwd[ 0 ], self.forget_pwd[ 1 ])
class LoginHandle :
"""
操作层
"""
def __init__ (self) :
self.login_page = LoginPage()
def input_username (self, username) :
self.login_page.find_username().clear()
self.login_page.find_username().send_keys(username)
def input_password (self, pwd) :
self.login_page.find_password().clear()
self.login_page.find_password().send_keys(pwd)
def input_verify_code (self, code) :
self.login_page.find_verify_code().clear()
self.login_page.find_verify_code().send_keys(code)
def click_login_btn (self) :
self.login_page.find_login_btn().click()
def click_forget_pwd (self) :
self.login_page.find_forget_pwd().click()
class LoginProxy :
"""
业务层
"""
def __init__ (self) :
self.login_handle = LoginHandle()
# 登录
def login (self, username, password, verify_code) :
# 输入用户名
self.login_handle.input_username(username)
# 输入密码
self.login_handle.input_password(password)
# 输入验证码
self.login_handle.input_verify_code(verify_code)
# 点击登录按钮
self.login_handle.click_login_btn()
# 跳转到忘记密码页面
def to_forget_pwd_page (self) :
# 点击忘记密码
self.login_handle.click_forget_pwd()
PO 模式深入封装
目标
1. 能够采用继承的思想对 PO 模式进行深入的封装
1. V6 版本
把共同操作提取封装到父类中,子类直接调用父类的方法,避免代码冗余
1.
对象库层 - 基类,把定位元素的方法定义在基类中
2.
操作层 - 基类,把对元素执行输入操作的方法定义在基类中
1.1 示例代码
# base_page.py
from po.utils import DriverUtil
class BasePage :
"""
基类 - 对象库层
"""
def __init__ (self) :
self.driver = DriverUtil.get_driver()
def find_element (self, location) :
return self.driver.find_element(location[ 0 ], location[ 1 ])
class BaseHandle :
"""
基类 - 操作层
"""
def input_text (self, element, text) :
"""
在输入框里输入文本内容,先清空再输入
:param element: 要操作的元素
:param text: 要输入的文本内容
"""
element.clear()
element.send_keys(text)
from selenium.webdriver.common.by import By
from po.v6.common.base_page import BasePage, BaseHandle
class LoginPage (BasePage) :
"""
对象库层
"""
def __init__ (self) :
super().__init__()
# 用户名输入框
self.username = (By.ID, "username" )
# 密码
self.password = (By.ID, "password" )
# 验证码
self.verify_code = (By.ID, "verify_code" )
# 登录按钮
self.login_btn = (By.NAME, "sbtbutton" )
# 忘记密码
self.forget_pwd = (By.PARTIAL_LINK_TEXT, " 忘记密码 " )
def find_username (self) :
return self.find_element(self.username)
def find_password (self) :
return self.find_element(self.password)
def find_verify_code (self) :
return self.find_element(self.verify_code)
def find_login_btn (self) :
return self.find_element(self.login_btn)
def find_forget_pwd (self) :
return self.find_element(self.forget_pwd)
class LoginHandle (BaseHandle) :
"""
操作层
"""
def __init__ (self) :
self.login_page = LoginPage()
def input_username (self, username) :
self.input_text(self.login_page.find_username(), username)
def input_password (self, pwd) :
self.input_text(self.login_page.find_password(), pwd)
def input_verify_code (self, code) :
self.input_text(self.login_page.find_verify_code(), code)
def click_login_btn (self) :
self.login_page.find_login_btn().click()
def click_forget_pwd (self) :
self.login_page.find_forget_pwd().click()
class LoginProxy :
"""
业务层
"""
def __init__ (self) :
self.login_handle = LoginHandle()
# 登录
def login (self, username, password, verify_code) :
# 输入用户名
self.login_handle.input_username(username)
# 输入密码
self.login_handle.input_password(password)
# 输入验证码
self.login_handle.input_verify_code(verify_code)
# 点击登录按钮
self.login_handle.click_login_btn()
# 跳转到忘记密码页面
def to_forget_pwd_page (self) :
# 点击忘记密码
self.login_handle.click_forget_pwd()

你可能感兴趣的:(测试工具,单元测试)