基本概念:
库
库的英文单词是Library,库是由代码及合成的一个产品,可供程序员调用。面向对象的代码组织形成的库叫做类库,面向过程的代码组织形成的库叫做函数库。从这个角度看,第4章介绍的WebDriver就属于库的范畴,因为它提供了一组操作Web页面的类与方法,所以可以称它为Web自动化测试库。
框架
框架的英文单词是Framework,框架是为了解决一个或一类问题而开发的产品,用户一般指需要使用框架提供的类和函数,即可时i西安全部功能。从这个角度看,unittest框架(第六章)主要用于测试用例的组织执行,以及测试结果的生成。因为它的主要任务就是帮助我们完成测试工作,所以通常称它为测试框架。
工具
工具的英文单词是Tools,工具与框架所做的事情类似,只是工具提供了更高层次的封装,屏蔽了底层的代码,提供了单独的操作界面供用户使用。例如,UFT(QTP)、Katalon就属于自动化测试工具。
自动化测试模型
自动化测试模型可分为线性测试、模块化与类库、数据驱动侧后和关键字驱动测试,下面分别介绍这几种自动化测试模型的特点。
线性测试:
通过录制或编写对应程序的操作步骤会产生相应的线性脚本,每个线性脚本相对独立,且不产生依赖与调用。这是早期自动化测试的一种形式,即单纯地模拟用户完整的操作场景。第四章中的自动化测试例子就属于线性测试。
模块化与类库:
线性测试的缺点是不易维护,因此早期的自动化测试专家开始思考用新的自动化测试模型来代替线性测试。做法很简单,借鉴了编程语言中的模块化思想,把重要的操作单独封装成公共模块。在测试用例执行过程中,当需要用到模块封装时对其进行调用,这样就最大限度地消除了重复,从而提高测试用例的可维护性。
数据驱动测试:
虽然模块化测试很好地解决了脚本的重复问题,但是,自动化测试脚本在开发过程中还是发现了诸多不便。例如,在测试不同用户登录时,虽然登录的步骤是一样的,但是登录用的数据是不同的。模块化测试并不能解决这类问题。于是,数据驱动测试的概念被提出。
数据驱动测试的定义:
数据的改编曲东自动化测试的执行,最终引起测试结果的改变。简单理解就是把数据驱动所需要的测试数据参数化,我们可以用多种方式来存储和管理这些参数化的数据。
关键字驱动测试:
关键字驱动测试又被称为表驱动测试或基于动作字测试。这类框架会把自动化操作封装为"关键字",避免测试人员直接接触代码,多以"填表格"的形式降低脚本的编写难度。
模块化与参数化
模块化与参数化一般需要配合使用,即在创建函数或类方法时为它们设置入参,从而使它们可以根据不同的参数执行相应的操作。
下面用一个简单的例子介绍它们的用法。创建一个邮箱测试脚本test_mail.py。
driver = webdriver.Chrome()
driver.get("http://www.126.com")
#登录
sleep(2) # 挂起2毫秒
driver.swith_ro.frame("x-URS-iframe") # 切换表单
driver.find_element_by_name("email").clear() # 通过定位清空数据
driver.find_element_by_name("email").send_keys("username") # 通过定位输入数据(用户名)
driver.find_element_by_name("password").clear() # 通过定位清空数据
driver.find_element_by_name("password").send_keys("password") # 通过定位输入数据(密码)
driver.find_element_by_id("dologin").click() # 点击事件
# 登录之后的动作
slee(5) # 挂起5毫秒
# 退出
driver.find_element_by_link_text("退出").click()
# 关闭窗口
driver.quit()
假设要实现一个关于邮箱的自动化测试项目,那么可能每条测试用例都需要有登录动作和退出动作。大部分测试用例都是在登录之后进行的,例如,发邮件,查看、删除、搜索邮件等。此时,需要创建一个新的module.py文件来存放登录动作和退出动作。
class Mail:
# 初始化驱动
def __init__(self, driver)
def login(self):
"""登录"""
self.driver.switch_to.frame("x-URS-iframe") # 切换表单
self.driver.find_element_by_name("email").clear() # 清空数据
self.driver.find_element_by_name("email").send_keys("username") # 输入用户名
self.driver.find_element_by_name("password").clear() #清空数据
self.driver.find_element_by_name("password").send_keys("password") # 输入密码
self.driver.find_element_by_id("dologin").click() # 点击事件
def logout(self):
"""退出"""
self.driver.find_element_by_link_text("退出").click()
首先创建一个Mail类,在__init__()初始化方法中接收driver驱动并赋值给self.driver。在login()和logout()方法中分别使用self.driver实现邮箱的登录动作和退出动作。
接下来修改test_mail.py,测试调用Mail类中的login()和logout()方法。
from time import sleep
from selenium import webdriver
from module import Mail:
driver = webdriver.Chrome() # 创建对象
driver.get("http://www.126.com") # 建立连接
# 调用Mail类并接收driver驱动
mail = Mail(driver)
# 登录
mail.login()
# 登录之后的动作
sleep(5)
# 退出
mail.logout()
driver.quit()
在编写测试用例过程中,如果需要用到登录动作和退出动作,那么只需调用Mail类中的login()方法和logout()方法即可,这将大大提高测试代码的可复用性。
如果我们的需求是测试登录功能呢?虽然登录步骤是固定的,但是测试的数据(账号)不同,这时就需要把login()方法参数化。修改module.py文件代码如下。
#....
def login(self, username, password):
"""登录"""
self.driver.switch_to.frame("x-URS-iframe")
self.driver.find_element_by_name("email").clear()
self.driver.find_element_by_name("email").send_keys(username)
self.driver.find_element_by_name("password").clear()
self.driver.find_element_by_name("password").send_key(password)
self.driver.find_element_by_id("dologin").click()
这样就进一步提高了login()方法额可复用性,它不再使用一个固定的账号登录,而是根据被调用者传来的用户名和密码执行登录动作。
在测试用例中,可以用不同的数据调用login()方法。
# 调用Mail类
mail = Mail(driver)
# 登录账号为空
mail.login("","")
# 用户名为空
mail.login("","password")
# 密码为空
mail.login("username","")
# 用户名/密码错误
mail.login("error","error")
# 管理员登录
mail.login("admin","admin123")
根据selenium3书籍编写