1、Selenium Grid简介
Selenium Grid组件专门用于远程分布式测试或并发测试。使用此组件可以在一台计算机上给多台计算机(不同操作系统和不同版本浏览器环境)分发多个测试用例从而并发执行,
大大提高了测试用例的执行效率,基本满足大型项目自动化测试的时限要求和兼容性要求。
Selenium Grid使用Hub和Node模式,一台计算机作为Hub(管理中心)管理其他多个Node(节点)计算机,Hub负责将测试用例分发给多台Node计算机执行,并收集多台Node计算机执行结果的报告,汇总后提交一份总的测试报告。
Hub:
>在分布式测试模式中,只能有一台作为Hub的计算机
>Hub负责管理测试脚本,并负责发送脚本给其他Node节点
>所有的Node节点计算机必须先在作为Hub的计算机中进行注册,注册成功后再和Hub计算机通信,Node节点计算机会告之Hub自己的相关信息,例如,Node节点的操作系统和浏览器相关版本。
Node:
>在分布式测试模式中,可以有一个或多个Node节点
>Node节点会打开本地的浏览器完成测试任务并返回测试结果给Hub
>Noel节点的操作系统和浏览器版本无需和Hub保持一致
>在Node节点上可以同时打开多个浏览器并行执行测试任务
2、分布式自动化测试环境准备
(1)下载 JDK 1.8安装文件(最好从官网下载)
(2)安装JDK
(3)配置环境变量(1.8后的JDK会自动添加环境变量)
(4)在CMD中输入java -version命令后回车,显示出java信息,不报错说明安装成功
3、Selenium Grid的使用方法
(1)远程调用Firefox浏览器进行自动化测试(其他浏览器同理)
具体步骤如下:
1)找两台WIndows系统的计算机A和B,A计算机作为Hub,B计算机作为Node(如果没有可以用本机即作Hub又作Node)
2)两台计算机均访问http://www.seleniumhq.org/download,单击“Selenium Standalone Server”下的“Download Version x.x.x”进行下载,并保存在两台计算机的存放Webdriver驱动的目录中(如D盘根目录)
3)在机器A上打开CMD窗口,并当前工作目录切换到D盘根目录,然后执行如下语句:
java -jar selenium-server-standalone-3.141.59.jar -role hub (不报错即成功)
-role hub : 启动一个Hub服务,作为分布式管理中心,等待webdriver客户端进行注册和请求,默认接收注册的地址为:http://localhost:4444/grid/register,默认启动端口为4444
4)在机器A(假如Ip地址为192.168.1.123)中的Firefox浏览器(其他浏览器也可以)地址栏中访问http://localhost:4444/grid/console,如果访问的网页中显示出“view config”的链接,表示Hub已经成功启动
5)在机器B(假如Ip地址为192.168.1.124)中打开CMD窗口,将当前工作目录D盘根目录(即selenium-server-standalone-3.141.59.jar和Webdriver驱动所在目录),输入如下命令:
运行Firefox:
java -jar selenium-server-standalone-3.141.59.jar -role webdriver -hub http://192.168.31.94:4444/grid/register-Dwebdriver.firefox.driver="D:geckodriver.exe" -port 6666 -maxSession 5 -browser browserName="firefox",maxInstances=5
运行Chrome:
java -jar selenium-server-standalone-3.141.59.jar -role webdriver -hub http://192.168.31.94:4444/grid/register-Dwebdriver.chrome.driver="D:chromedriver.exe" -port 6666 -maxSession 5 -browser browserName="chrome",maxInstances=5
运行IE:
java -jar selenium-server-standalone-3.141.59.jar -role webdriver -hub http://192.168.31.94:4444/grid/register-Dwebdriver.ie.driver="D:IEDriverServer.exe" -port 6666 -maxSession 5 -browser browserName="internet explorer",maxInstances=5
运行三个浏览器:
java -jar selenium-server-standalone-3.141.59.jar -role webdriver -hub http://172.29.10.127:4444/grid/register-Dwebdriver.chrome.driver="e:chromedriver.exe"-Dwebdriver.ie.driver="e:IEDriverServer.exe"-Dwebdriver.firefox.driver="e:geckodriver.exe" -port 6666 -maxSession 5 -browser browserName="internet explorer",maxInstances=5 -browser browserName="chrome",maxInstances=5 -browser browserName="firefox",maxInstance=5
参数说明:
>role : 参数值wevdriver表示Node节点名字
>hub : 参数值表示管理中心的Url地址,Node会连接到这个地址进行节点注册
>port : 参数值表示Node节点服务的端口号为6666,建议使用大于5000的端口号
6)再次访问http://localhost:4444/grid/console,验证Node节点是否已在Hub上注册成功
7)分布式执行的测试脚本
测试逻辑:
使用FireFox浏览器访问sogou首页,进行关键词“webdriver 实战宝典”的搜索,并验证搜索结果页面源码中是否出现作者名称
测试脚本:
#encoding=utf-8 from selenium import webdriver from selenium.webdriver.common.keys import Keys import time driver = webdriver.Remote( #设定Node节点的Url地址,后续将通过这个地址连接到Node计算机 command_executor = "http://localhost:6666/wd/hub", desired_capabilities = { #指定远程计算机执行使用的浏览器 "browserName":"internet explorer", "video":"True", #远程计算机的平台 "platform":"WINDOWS" #"platform":"windows_nt" } ) print ("Video" + "http://www.baidu.com" + driver.session_id) try: driver.implicitly_wait(30) driver.maximize_window() driver.get("http://www.sogou.com") assert u"搜索" in driver.title ele = driver.find_element_by_id("query") ele.send_keys(u"webdriver 实战宝典") ele.send_keys(Keys.RETURN) time.sleep(3) assert u"吴晓华" in driver.page_source print "done!" finally: driver.quit()
测试结果:在机器B上可以看到,计算机会自动启动浏览器执行测试脚本,执行完毕后浏览器会自动退出。在机器A上可以看到自动化测试的执行结果
4、实现并发的分布式自动化测试
Selenium Grid不仅支持在同一台机器上同时启动好几个浏览器并发跑测试用例,也支持同时在多台不同机器上启动不同的浏览器并发跑测试用例。
操作步骤:
(1)在机器A、B和C的D盘根目录(Webdriver驱动所在目录)放入selenium-server-standalone-3.141.59.jar
(2)机器A启动Hub服务
(3)机器A重新打开一个CMD,并注册为节点
(4)机器B、机器C打开Cmd,并注册为节点
注意:注册的A、B和C机器节点的端口号必须不一致
测试脚本:
#encoding=utf-8 from multiprocessing import Pool import os, time from selenium import webdriver from selenium.webdriver.common.keys import Keys from multiprocessing import Manager, current_process def node_task(name, lock, arg, successTestCases, failTestCases): # 获取当前进程名 procName = current_process().name print procName time.sleep(1.2) print arg['node'] print arg["browerName"] print 'Run task %s (%s)... ' % (name, os.getpid()) start = time.time() driver = webdriver.Remote( command_executor = "%s" %arg['node'], desired_capabilities={ "browserName": "%s" %arg["browerName"], "video": "True", "platform": "WINDOWS"}) try: driver.implicitly_wait(30) driver.maximize_window() driver.get("http://www.sogou.com") assert u"搜狗" in driver.title elem = driver.find_element_by_id("query") elem.send_keys(u"webdriver实战宝典") time.sleep(2) elem.send_keys(Keys.RETURN) assert u"吴晓华" not in driver.page_source # 请求获取共享资源的锁 lock.acquire() # 向进程间共享列表successTestCases中添加执行成功的用例名称 successTestCases.append("TestCase" + str(name)) # 释放共享资源的锁,以便其他进程能获取到此锁 lock.release() print "TestCase" + str(name) + " done!" except AssertionError,e: print "AssertionError occur!""testCase" + str(name) print e # 截取屏幕 driver.save_screenshot('e:\screenshoterror' + str(name) + '.png') lock.acquire() # 向共享列表failTestCases中添加执行失败的用例名称 failTestCases.append("TestCase" + str(name)) lock.release() print u"测试用例执行失败" except Exception,e: print "Exception occur!" print e driver.save_screenshot('e:\screenshoterror' + str(name) + '.png') # 请求获得共享资源操作的锁,操作完后自动释放 with lock: # 向共享列表failTestCases中添加执行失败的用例名称 failTestCases.append("TestCase" + str(name)) print u"测试用例执行失败" finally: driver.quit() end = time.time() print 'Task %s runs %0.2f seconds.' % (name, (end - start)) def run(nodeSeq): # 创建一个多进程的Manager实例 manager = Manager() # 定义一个共享资源列表successTestCases successTestCases = manager.list([]) # 定义一个共享资源列表failTestCases failTestCases = manager.list([]) # 创建一个资源锁 lock = manager.Lock() # 打印主进程的进程ID print 'Parent process %s.' % os.getpid() # 创建一个容量为3的进程池 p = Pool(processes=3) testCaseNumber = len(nodeSeq) for i in range(testCaseNumber): # 循环创建子进程,并将需要的数据传入子进程 p.apply_async(node_task, args=(i + 1, lock, nodeSeq[i], successTestCases, failTestCases)) print 'Waiting for all subprocesses done...' # 关闭进程池,不再接受新的请求任务 p.close() # 阻塞主进程直到子进程退出 p.join() return successTestCases, failTestCases def resultReport(testCaseNumber, successTestCases, failTestCases): # 下面代码用于打印本次测试报告 print u"测试报告: " print u"共执行测试用例:" + str(testCaseNumber) + u"个 " print u"成功的测试用例:", str(len(successTestCases)) if len(successTestCases) > 0: for t in successTestCases: print t else: print u"无" print u"失败的测试用例:", str(len(failTestCases)) if len(failTestCases) > 0: for t in failTestCases: print t else: print u"无" if __name__ == '__main__': # 节点列表 nodeList=[ {"node":"http://127.0.0.1:6666/wd/hub","browerName":"internet explorer"}, {"node":"http://127.0.0.1:6666/wd/hub","browerName":"chrome"}, {"node":"http://127.0.0.1:6666/wd/hub", "browerName":"firefox"}] # 获取节点个数 testCaseNumber = len(nodeList) # 开始多进程分布式测试 successTestCases, failTestCases = run(nodeList) print 'All subprocesses done.' # 在控制台中打印测试报告 resultReport(testCaseNumber, successTestCases, failTestCases)
5、注意点:
jar和Webdriver浏览器驱动放在同一目录下
机器A:启动Hub
机器B:注册到这个Hub
程序:在机器A运行,然后指定机器B的ip作为driver的参数,然后可以在机器B运行测试程序