WebDriver 封装
欢迎阅读WebDriver封装讲义。本篇讲义将会重点介绍Selenium WebDriver API的封装的概念和方法,以及使用封装进行自动化测试的设计。
WebDriver API 封装
封装的概念
从之前的讲义和学习中,我们知道,WebDriver API的调用以及自动化测试,我们也初步接触了线性测试、以及模块化自动化测试和数据驱动测试,那么回顾之前的内容,我们不只是可以利用WebDriver提供的一系列的定位符以便使用元素定位方法,我们这里开始尝试封装后调用。首先,我们从封装的概念开始。
封装是一个面向对象编程的概念,是面向对象编程的核心属性,通过将代码内部实现进行密封和包装,从而简化编程。
所谓“对象”,形象地说,我们可以把它理解为一块积木。设计积木的人需要设计积木的外观与形状,还有内部的材质。堆积木的人对于内部的材质并不关心,他们只需要根据不同的外观与形状来决定堆放的位置。因此,对于开发者而言,要设计面向对象的程序,同时会是两个迥然不同的身份:设计者与使用者。
先谈谈使用者。使用者的身份,就是利用已经提供给你的所有对象,根据需求,设计出自己需要实现的程 序。就如堆积木的过程。这恰恰是面向对象编程的优势所在,那就是“对象的重用”。已经设计好的对象,可以被不同的使用者调用,这些功能既然已经实现,对于使用者而言,当然就免去了自己去设计的过程。正如堆积木那样,既然有了现成设计好的积木,使用者所要做的工作就是把这些积木最后组合起来,堆成不同的形状。WebDriver
所提供的类库,就是这样的积木。那么我们以下的操作将会基于上述的定位符进行定位操作。
前面说到对象好比是一个积木,设计者需要定义好这个积木的外观和形状,也要考虑积木内部的制作,例如选用的材质,以及是空心还是实心。如果将这个积木剖开来看,实际上该对象应分为内、外两层。由于使用者只关心外部的实现,因此设计者就需要考虑,哪些实现应暴露在外,哪些实现应隐藏于内。这就体现了对象的封装的思想。
简而言之,封装就是把原始和原生的方法进行再包装。将原始的代码用心的代码包装起来,通过对新代码的调用,来使用原始的代码的过程。
封装的好处
对Selenium进行封装的好处主要有如下三个方面:
- 使用成本低
- 不需要要求所有的测试工程师会熟练使用Selenium,而只需要会使用封装以后的代码
- 不需要对所有的测试工程师进行完整培训。也避免工作交接的成本。
- 测试人员使用统一的代码库
- 维护成本低
- 通过封装,在代码发生大范围变化和迁移的时候,不需要维护所有代码,只需要变更封装的部分即可
- 维护代码不需要有大量的工程师,只需要有核心的工程师进行封装的维护即可
- 代码安全性
- 对作为第三方的Selenium进行封装,是代码安全的基础。
- 对于任何的代码的安全隐患,必须由封装来解决,使得风险可控。
- 使用者并不知道封装内部的代码结构。
封装的目的
封装,最终为了实现自动化测试框架。在自动化测试领域,有一个经典的问题:“既然可以编写或者通过record & playback可以做一个脚本,那么为什么还需要自动化测试框架呢?”简而言之,就是为什么需要如此这般麻烦的设计和编写自动化测试框架,不是原本已经可以做自动化测试了么?
这个回答可以很“官方”,从维护性、重用性、安全性和成本等角度可以回答。
在这点,就好比是建造房子。在没有设计框架的基础上,我们或许可以建造一个楼房,最多也就三两层吧;但是对于一份经过完整设计的图纸,人们可以建造出高楼大厦。
封装,就是把基础的石头等建材,通过我们的个性化的方法,将地基可用而安全的搭建好。是自动化测试框架的基石。
使用封装进行自动化测试
封装示例
测试脚本:以下的脚本
def getElement(self, selector):
"""
to locate element by selector
:arg
selector should be passed by an example with "i,xxx"
"x,//*[@id='langs']/button"
:returns
DOM element
"""
if ',' not in selector:
return self.driver.find_element_by_id(selector)
selector_by = selector.split(',')[0]
selector_value = selector.split(',')[1]
if selector_by == "i" or selector_by == 'id':
element = self.driver.find_element_by_id(selector_value)
elif selector_by == "n" or selector_by == 'name':
element = self.driver.find_element_by_name(selector_value)
elif selector_by == "c" or selector_by == 'class_name':
element = self.driver.find_element_by_class_name(selector_value)
elif selector_by == "l" or selector_by == 'link_text':
element = self.driver.find_element_by_link_text(selector_value)
elif selector_by == "p" or selector_by == 'partial_link_text':
element = self.driver.find_element_by_partial_link_text(selector_value)
elif selector_by == "t" or selector_by == 'tag_name':
element = self.driver.find_element_by_tag_name(selector_value)
elif selector_by == "x" or selector_by == 'xpath':
element = self.driver.find_element_by_xpath(selector_value)
elif selector_by == "s" or selector_by == 'selector_selector':
element = self.driver.find_element_by_css_selector(selector_value)
else:
raise NameError("Please enter a valid type of targeting elements.")
return element
def type(self, selector, text):
"""
Operation input box.
Usage:
driver.type("i,el","selenium")
"""
el = self.getElement(selector)
el.clear()
el.send_keys(text)
以上的代码是封装了find_element_by_
的几种方法,在具体使用封装过的代码的时候,只需要简单的调用即可。
调用示例
def login(self, userName, password):
self.openPage(self.loginPageUrl)
# self.driver.clearCookies()
self.driver.implicitlyWait(5)
self.driver.type("account", userName)
self.driver.type("password", password)
self.driver.click("submit")
自动化的测试代码示例
def test_ranzhi_login(self):
"""
测试用例:测试然之登录
:return:
"""
# 新建然之的页面对象
loginPage = RanzhiSubLoginPage(self.autoDriver, self.baseUrl)
# 利用然之的页面对象进行登录
loginPage.login("admin", "admin")
sleep(2)
# 断言 是否登录成功
self.assertEqual(loginPage.getMainPage(), self.autoDriver.getUrl(), u"登录失败")