在Selenium家族中,我们已经学习了WebDriver,本章将介绍最后一位成员——Selenium Grid。利用Selenium Grid可以在不同的主机上建立主节点(hub)和分支节点(node),可以使主节点上的测试用例在不同的分支节点上运行。对不同的节点来说,可以搭建不同的测试环境(操作系统、浏览器),从而使一份测试用例得到不同环境下的执行结果,进而实现了并行的兼容性测试。
Selenium Grid版本
现在的Selenium Grid2完全能支持Selenium 2的所有功能。The Selenium Server is needed in order to run Remote Selenium WebDriver (Grid).
Grid2同时支持Selenium 1和Selenium 2两种协议,并且在一些小的功能和易用性上进行了优化,例如,指定测试平台的方式等。
Grid2不再提供单独的包,其功能已经集成到 Selenium Server中,所以,需要下载和运行Selenium Server才可以使用Grid2的功能。
9.1 Selenium Server环境配置
下面下载、配置并运行Selenium Server。
① 下载Selenium Server。
下载地址为:http://www.seleniumhq.org/download/
Latest stable version 3.141.59
To use the Selenium Server in a Grid configuration see the documentation
通过浏览器打开页面,找到Selenium Standalone Server的介绍,单击版本号链接下载,例如Download v ersion 2.48.2,下载完成后将得到selenium-server-standalone-xxx.jar。由于该jar包由Java开发,所以对于jar包的运行需要Java环境。
② 配置Java环境。
Java下载地址为:http://www.java.com/zh_CN/download/manual.jsp
Java环境分为JDK和JRE两种。JDK的全称为Java Development Kit,JDK是面向开发人员使用的SDK,它提供了Java的开发环境和运行环境。JRE的全称为Java Runtime Environment,是指Java的运行环境,面向的是Java程序的使用者,而不是开发者。
根据本机操作系统环境选择相应的版本进行下载,安装完成后,设置环境变量,右击“计算机”,在弹出的右键单中单击属性→高级系统设置→环境变量→系统变量
变量名:JAVA_HOME 变量值:C:Program FilesJavajdk1.7.0_45 变量名:CALSS_PATH 变量值:.;%JAVA_HOME%libdt.jar;%JAVA_HOME%lib ools.jar; 变量名:path 变量值:%JAVA_HOME%in;%JAVA_HOME%jrein;
在Windows命令提示符下验证Java环境是否配置成功。
“java”命令用于运行class文件字节码。
“javac”命令可以将Java源文件编译为class字节码文件。
③ 运行Selenium Server。
现在可以通过“java”命令运行Selenium Server了。切换到Selenium Server所在目录下并启动,如图9.2所示。在Windows命令提示符(或MacOSX终端)下启动Selenium Server。
> java -jar selenium-server-standalone-2.47.0.jar
9.2 Selenium Grid工作原理
Grid是用于设计帮助我们进行分布式测试的工具,其整个结构由一个hub主节点和若干个node代理节点组成。hub用来管理各个代理节点的注册和状态信息,并且接收远程客户端代码的请求调用,然后把请求的命令再转发给代理节点来执行。使用Grid远程执行测试的代码与直接调用Selenium Server是一样的,只是环境启动的方式不一样,需要同时启动一个hub和至少一个node。
> java -jar selenium-server-standalone-x.xx.x.jar -role hub
> java -jar selenium-server-standalone-x.xx.x.jar -role node
上面的代码分别启动了一个hub和一个node,hub默认端口号为4444,node默认端口号为5555。若是同一台主机上要启动多个node,则需要注意指定端口号,可以通过下面的方式来启动多个node点节。
> java -jar selenium-server-standalone-x.xx.x.jar -role node -port 5555 > java -jar selenium-server-standalone-x.xx.x.jar -role node -port 5556 > java -jar selenium-server-standalone-x.xx.x.jar -role node -port 5557
当你的测试用例需要验证的环境比较多时,可以并行地执行这些用例进而缩短测试总耗时。并行的能力需要借助编程语言的多线程技术,本教程第11章将会介绍Python的多线程技术。Grid可以根据用例中指定的平台配置信息把用例转发给符合匹配要求的测试代理。例如,你的用例中指定了要在Linux上用Firefox版本进行测试,那么Grid会自动匹配注册信息为Linux且安装了Firefox的代理节点,如果匹配成功,则转发测试请求,如果匹配失败则拒绝请求。调用的基本结构图如图9.4所示。
下面在同一台主机上启动一个hub主节点和两个node分支节点,如图9.5所示。
通过浏览器访问Grid的控制台:http://127.0.0.1:4444/grid/console。
通过控制台查看启动的节点信息,如图9.6所示。
9.3 Remote应用
要解释清楚Remote的作用并不太容易,不过我们可以通过分析Selenium代码的方式来理解它的作用。我们知道WebDriver支持多浏览器下的执行,这是因为WebDriver针对每一种浏览器驱动都重写WebDriver方法。所以,在脚本运行之前需要先确定浏览器驱动,具体如下:
driver = webdriver.Firefox()
driver = webdriver.Chrome()
driver = webdriver.Ie()
下面就对这些驱动进行简单分析。
9.3.1 WebDriver驱动分析
在selenium包的webdriver目录下可以看到如图9.7所示的目录结构。
查看其中任何一个驱动的目录发现都有一个webdriver.py文件,除了我们熟悉的Firefox、Chrome、IE等驱动外,其中还包括非常重要的remote。从这个角度看,也可以把它看作是一种驱动类型,而这种驱动类型比较特别,它不是支持某一款特定的浏览器或平台,而是一种配置模式,我们在这种配置模式下指定任意的平台或浏览器,这种模式的执行都需要Selenium Server的支持。
打开selenium包下的webdriver/firefox目录,先看Fireofox中webdriver.py文件的实现。
webdriver.py
主机查看WebDriver类的__init__()初始化方法,因为Selenium自带Firefox浏览器驱动,所以,这个驱动的重要配置在于firefox_profile和firefox_binary两个参数。而这两个参数分别调用当前目录下的firefox_binary.py和firefox_profile.py文件,感兴趣的读者可以进一步研究这两个文件的实现。
我们在脚本中调用Firefox浏览器驱动时的路径为:selenium.webdriver.Firefox(),那么,它是如何指向../selenium/webdriver/firefox/webdriver.py文件中WebDriver类的呢?秘密在于../selenium/webdriver/目录下的__init__.py文件。
__init__.py …… from .firefox.webdriver import WebDriver as Firefox from .firefox.firefox_profile import FirefoxProfile from .chrome.webdriver import WebDriver as Chrome from .chrome.options import Options as ChromeOptions from .ie.webdriver import WebDriver as Ie from .edge.webdriver import WebDriver as Edge from .opera.webdriver import WebDriver as Opera from .safari.webdriver import WebDriver as Safari from .blackberry.webdriver import WebDriver as BlackBerry from .phantomjs.webdriver import WebDriver as PhantomJS from .android.webdriver import WebDriver as Android from .remote.webdriver import WebDriver as Remote from .common.desired_capabilities import DesiredCapabilities from .common.action_chains import ActionChains from .common.touch_actions import TouchActions from .common.proxy import Proxy __version__ = '2.47.0'
通过查看该文件就明白了它的原理,它其实对不同驱动的路径做了简化,并且将不同目录下的WebDriver类重命名为相应的浏览器(Firefox、Chrome、IE等),所以,在调用不同浏览器的驱动时就简化了层级。
再打开selenium包下的webdriver/chrome目录,查看Chrome中webdriver.py文件的实现。
样查看WebDriver类的__init__()初始化方法,因为Selenium模块不自带chromedriver.exe驱动,所以,executable_path参数会指定chromedriver驱动。
通过查看两个文件注意到一个细节,是Firefox和Chrome的WebDriver类都继承RemoteWebDriver类,也就是remote的WebDriver类,那么我们很好奇这个WebDriver类实现了什么功能?
打开selenium包下webdriver/remote目录下的webdriver.py文件。
WebDriver类的__init__()初始化方法提供了一个重要信息,即command_executor参数,它默认指向本机(127.0.0.1)的4444端口号,通过修改这个参数可以使其指向任意的某台主机。
除此之外,我们还需要对浏览器进行配置。浏览器的配置由desired_capabilities参数决定,这个参数的秘密在selenium包的webdriver/common目录下的desired_capabilities.py文件中。
DesiredCapabilities平台及浏览器的参数如下
FIREFOX = {"browser Name": "firefox", "version": "", "plat form": "ANY","javascriptEnabled": True, "marionette": False, } INTERNETEXPLORER = {"browserName": "internet explorer", "version": "", "platform": "WINDOWS", "javascriptEnabled": True, } EDGE = {"browserName": "MicrosoftEdge", "version": "", "platform": "WINDOWS" } CHROME = {"browserName": "chrome", "version": "", "platform": "ANY", "javascriptEnabled": True, } OPERA = {"browserName": "opera", "version": "", "platform": "ANY", "javas criptEnabled": True, } SAFARI = {"browserName": "safari", "ve rsion": "", "pla tform": "ANY", "javascriptEnabled": True, } HTMLUNIT = {"browserName": "htmlunit", "version": "", "platform": "ANY", } HTMLUNITWITHJS = {"browserName": "htmlunit", "version": "firefox","platform": "ANY", "javascriptEnabled": True, } IPHONE = {"browserName": "iPhone", "version": "", "platform": "MAC", "javascriptEnabled": True, } IPAD = {"browserName": "iPad", "version": "", "platform": "MAC", "javascriptEnabled": True, } ANDROID = {"browserName": "android", "version": "", "platform": "ANDROID", "javascriptEnabled": True, } PHANTOMJS = {"browserName":"phantomjs", "version": "", "platform": "ANY", "javascriptEnabled": True,}
值得一提的是,在Windows 10发布当天,Selenium更新到了2.47.0版本,第一时间支持了基于Windows 10的旧版的 Edge浏览器。
9.3.2 Remote实例
下面通过Remote来运行测试用例。
首先,通过Windows命令提示符(或Linux终端)启动Selenium Server。
> java -jar selenium-server-standalone-2.47.0.jar
编写自动化测试脚本。
remote_ts.py
from selenium.webdriver import Remote # 调用Remote方法 driver = Remote(command_executor='http://127.0.0.1:4444/wd/hub', desired_capabilities={'platform': 'ANY', 'browserName': 'chrome', 'version': '', 'javascriptEnabled': True } ) driver.get('http://www.baidu.com') driver.find_element_by_id("kw").send_keys("remote") driver.find_element_by_id("su").click() driver.quit()
从上面的Remote()方法配置来看,它相当于我们直接使用webdriver.Chrome(),但是Remote()却大大增加了配置的灵活性。
9.3.3 参数化平台及浏览器
通过Selenium Server可以轻松地创建本地节点和远程节点。而Remote的作用就是配置测试用例在这些节点上执行,下面就通过例子来演示它们两者的组合。
在本机打开cmd命令提示符窗口,分别启动一个hub和两个node(节点)。
> java -jar selenium-server-standalone-2.47.0.jar -role hub
> java -jar selenium-server-standalone-2.47.0.jar -role node -port 5555
> java -jar selenium-server-standalone-2.47.0.jar -role node -port 5556
下面修改脚本使其在不同的节点和浏览器上运行。
remote_ts.py
from selenium.webdriver import Remote # 定义主机与浏览器 lists = {'http://127.0.0.1:4444/wd/hub': 'chrome', 'http://127.0.0.1:5555/wd/hub': 'firefox', 'http://127.0.0.1:5556/wd/hub': 'internet explorer'} # 通过不同的浏览器执行脚本 for host, browser in lists.items(): print(host, browser) driver = Remote(command_executor=host, desired_capabilities={'platform': 'ANY', 'browserName':browser, 'version': '', 'javascriptEnabled': True } ) driver.get("http://www.baidu.com") driver.find_element_by_id("kw").send_keys(browser) driver.find_element_by_id("su").click() driver.close()
首先,创建lists字典,定义不同的主机IP、端口号及浏览器。然后,通过for循环读取lists字典中的数据作为Remote()的配置信息,从而使脚本在不同的节点及浏览器下执行。
1.启动远程node
我们目前启动的hub与node都是在同一台主机上,要想在其他主机上启动node,则必须满足以下要求。
本地hub主机与远程node主机之间可以用ping命令连通。
远程主机必须安装用例执行的浏览器及驱动,并且驱动要放在环境变量path的目录下。
远程主机必须安装Java环境,因为需要运行Selenium Server。
2.操作步骤
① 启动本地hub主机(本地主机IP为:172.16.10.66)。
> java -jarselenium-server-standalone-2.47.0.jar -role hub
② 启动远程node主机(操作系统:Ubuntu,IP地址:172.16.10.34)。
$ java -jars elenium-server-standalone-2.47.0.jar -role node -port 5555 -hub
http://172.16.10.66:4444/grid/register
设置的端口号为:5555,指向的hub主机IP为172.16.10.66。
③ 修改远程主机的IP地址及端口号,在其上面的Firefox浏览下运行脚本。
remote_ts.py
…… # 定义主机与浏览器 lists = {'http://127.0.0.1:4444/wd/hub':'chrome', 'http://127.0.0.1:5555/wd/hub':'internet explorer', 'http://172.16.10.34:5555/wd/hub': 'firefox'} ……
现在再来运行脚本,你将会在172.16.10.34主机上看到脚本被执行。
在启动Selenium Server时,每次都要输入一长串命令,非常麻烦。我们可以将启动命令生成批处理文件,方法很简单。首先创建一个startup.bat文件,例如,Selenium Server存放于D盘selenium目录下,那么可以在.bat文件中输入:
java -jar D:\seleniumselenium-server-standalone-2.47.0.jar -role hub
然后,在需要启动Selenium Server的时候双击startup.bat文件即可。
另外,我们还可以通过VisGrid工具来启动和管理节点,如图9.8所示。
9.4 WebDriver驱动
在9.3节中,我们对WebDriver驱动的实现进行了简单分析,到目前为止,我们所熟悉的浏览器驱动有:Firefox Driver、Chrome Driver和IEDriverServer等。除此之外,WebDriver还支持哪些平台及驱动呢?本节将会对这些驱动作简单介绍。
WebDriver所支持的平台/浏览器/模式如表9.1所示。
1.支持平台
WebDriver支持Android移动平台的浏览器测试,至于支持性如何,笔者并没有做过测试。Android目前为市场占有率第一的移动平台,对于在其上面进行自动化测试,笔者推荐Appium,Appium扩展了WebDriver的协议,支持iOS平台和Android平台上的原生应用、Web应用和混合应用等。
2.支持浏览器
WebDriver目前所支持的浏览器包括:Firefox、Chrome、IE、Edge、Safari。
为什么会选择上面几款浏览器进行支持呢?主要与浏览器的内核有关。
3.支持模式
HtmlUnit和PhantomJS是两个比较特殊的模式,我们可以把它们看作是伪浏览器,在这种模式下支持html、Java Saript等的解析,但不会真正地渲染出页面。由于不进行CSS及GUI渲染,所以运行效率上要比真实的浏览器快很多,主要用在功能性测试上面。
Safari浏览器
Safari为苹果公司的浏览器,最早支持MAC平台,不过,现在已经支持Windows平台。与其他浏览器有所不同,Safari浏览器没有相应的驱动文件,它的驱动被集成到了Selenium Server中,所以,需要通过Remote配置运行。
首先,在Windows命令提示符(或Linux终端)下启动Selenium Server。> java -jar selenium-server-standalone-2.47.0.jar,然后,运行脚本。
baidu.py
from selenium.webdriver import Remote dc = {'browserName': 'safari'} driver = Remote(command_executor=' http://127.0.0.1:4444/wd/hub', desired_capabilities=dc) driver.get("http://www.baidu.com") driver.find_element_by_id("kw").send_keys("safari") driver.find_element_by_id("su").click() driver.quit()
HtmlUnit模式
HtmlUnit官方网站:http://htmlunit.sourceforge.net/
HtmlUnit是一款开源的Java页面分析工具,读取页面后,可以有效地使用HtmlUnit分析页面上的内容。项目可以模拟浏览器运行,被誉为Java浏览器的开源实现。这个没有界面的浏览器,其运行速度非常迅速。Selenium Server中同样包含了HtmlUnit驱动。
首先,在Windows命令提示符(或Linux终端)下启动Selenium Server。
> java -jarselenium-server-standalone-2.47.0.jar
然后,运行脚本。
baidu.py
from selenium.webdriver import Remote from selenium.common.exceptions import WebDriverException dc = {'browserName': 'htmlunit'} driver = Remote(command_executor=' http://127.0.0.1:4444/wd/hub', desired_capabilities=dc) driver.get("http://www.baidu.com") driver.find_element_by_id("kw").send_keys("htmlunit") driver.find_element_by_id("su").click() driver.get_screenshot_as_file("D:\run_ok.jpg") driver.quit()
这种模式下运行脚本并不会真正地打开浏览器,整个过程都是在后台执行的。所以,为了证明运行是成功的,或者证明脚本确实执行了,可以在适当的步骤添加截图。
PhantomJS模式
PhantomJS官方网站:http://phantomjs.org/
PhantomJS是一个拥有JavaScript API的无界面WebKit内核,与HtmlUnit类似。正如我们所知道的,Webkit是Safari和其他一些浏览器使用的布局引擎。因此,PhantomJS是一个浏览器,而且是一个无界面的浏览器。这意味着渲染后的网页实际上绝不会显示。这或许有些不可思议,所以我们可以把它作为一个可编程的浏览器终端。
在使用PhantomJS之前,需要先下载它。PhantomJS支持Windows、MAC、Linux等平台,我们可以根据自己的环境选择相应的版本进行下载。
下载完成后解压得到phantomjs.exe程序,将其复制到C:Python35目录下,即可通过PhantomJS模式运行测试脚本。
baidu.py
from selenium import webdriver from time import sleep driver = webdriver.PhantomJS() driver.get("http://www.baidu.com") try: driver.find_element_by_id("kw").send_keys("phantomjs") driver.find_element_by_id("su").click() sleep(1) driver.get_screenshot_as_file("D:\baidu_ok.jpg") except WebDriverException as msg: print(msg) driver.get_screenshot_as_file("D:\baidu_error.jpg") finally: driver.quit()
通过HtmlUnit或PhantomJS进行的自动化测试运行不会真正打开一个浏览器,在我们看来,可见的东西才会觉得是真实的,这时可以在脚本必要的位置添加截图,另一方面,截图也可以帮助定位。打开D盘下的baidu_ok.jpg 截图。
本章小结
本章重点介绍了Selenium Grid的原理与使用,因为其被集成到了Selenium Server中,所以我们以Selenium Server为载体进行使用。接着对Remote代码实现做了简单分析,以及如何进行平台及浏览器的参数化。最后,介绍了测试用例在不同浏览器及模式下的运行。