【软件测试】自动化测试战零基础教程——Python自动化从入门到实战(十)

整理不易,希望对各位学习软件测试能带来帮助这里是引用

第九章 selenium grid2 分布式执行测试用例

我们在前面的章节中曾介绍过如何通过 python 的多线程来并行的在一台电脑上运行测试用例,Selenium Grid 允许用户将测试案例分布在几台机器上并行执行。用户可以在一个集中控制点控制不同的
环境。在不同的浏览器 / 系统组合上面更为容易的运行测试案例。允许用户更多的利用虚拟资源减少了维护测试环境的成本。
Selenium-Grid 版本
selenium-grid 分为版本 1 和版本 2,其实它的 2 个版本并不是和 selenium 的版本 1 和 2 相对应发布的(即 selenium-grid2 的发布比 selenium2 要晚一点)。不过幸运的是现在的 selenium-grid2 基本能支持selenium2 的所有功能了。

selenium 虽然分 1 和 2,但其实原理和基本工作方式都是一样的。只是版本 2 同时支持 selenium1 和
selenium2 两种协议,并且在一些小的功能和易用性上进行了优化。比如:指定测试平台的方式。

selenium grid2 已经集成到 selenium server 中了(即 selenium-server-standalone-XXX.jar 包中)
所以,我们不用单独下载与安装 selenium grid。

第一节、selenium1 与 2 工作原理

在介绍 selenium grid 的工作原理之前,我们有必要先理解 selenium 1 与 selenium 2 的工作原理的差异,这将有助于帮助我们理解和使用 selenium grid 。

Selenium 1 工作原理

selenium1 中除了使用 selenium-core 以外,进行自动化测试时都需要使用 selenium-RC 来作为代理
(不管是本机还是远程),目的是为了解决同源问题;而造成同源问题的原因是因为 selenium1 中是使用Javascript 来驱动测试执行的(浏览器由于安全问题不允许不同域之间的 JS 调用,即非同源不可调用;而 selenium1 中的工作方式就是在宿主页面注入 JS 并且通过调用 JS 来执行测试操作的,所以就涉及到同源问题)。所以为了达成目的,其解决方案就有 2 种:

1、使用 selenium-core:

selenium-core 是一组 js 库,用来驱动浏览器操作的所有库文件都在这里,整个 selenium1 可以认为核心组件就是这个 selenium-core;而使用 selenium-core 的方式就是在被测试站点程序的源码里把 selenium-core 中的所有 js 库直接添加到页面里,这样页面正常加载的同时也会把 selenium-core加载下来,并且天生就是同源的。

2、使用 selenium-RC:

RC 是一个 http 代理程序,用来注入到浏览器和被测 web 程序之间,这样浏览器所有的请求和接
收的内容都会通过 RC;RC 会把浏览器的请求发送给真实的 web 程序,而在接收到 web 程序的响应
内容时,并没有把内容原原本本的返回给浏览器客户端,而是把包含 selenium-core 的内容注入到响
应内容中去,然后才发送响应内容给浏览器,这样就通过欺骗的方式让浏览器认为 selenium1 的驱动
类库同样是同源的。

Selenium2 工作原理

selenium2 中因为使用的 webdriver,这个技术不是靠 js 驱动的,而是直接调用浏览器的原生态接口
驱动的。所以就没有同源问题,也就不需要使用 RC 来执行本地脚本了(当然缺点就是并不是所有的浏览器都有提供很好的驱动支持,但 JS 却是所有浏览器都通用的)。所以 selenium2 中执行本地脚本的方式是:通过本地 webdriver 驱动直接调用本地浏览器接口就可以了。
Selenium 1 与 selenium 2 代码对比
我们可以通过 selenium IDE 将录制的脚本导入出成 selenium 1 和 selenium 2 两种格式做对比
(selenium IDE 录制并导出脚本参考前面章节),按照惯例以录制百度人搜索为例:
Selenium 1 (RC) 代码:

from selenium import selenium
import unittest, time, re
class serc(unittest.TestCase):
def setUp(self):
self.verificationErrors = []
self.selenium = selenium("localhost", 4444, "*chrome", "http://www.baidu.com/")
self.selenium.start()
def test_serc(self):
sel = self.selenium
sel.open("/")
sel.type("id=kw", "selenium grid")
sel.click("id=su")
sel.wait_for_page_to_load("30000")
def tearDown(self):
self.selenium.stop()
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
unittest.main()

self.selenium = selenium(“localhost”, 4444, “*chrome”, “http://www.baidu.com/”)
明显的差异是在通过 selenium 操作之间我们要先指定代理的电脑,localhost 表示本机,4444 表示端口
号,以及运行的浏览器"*chrome" 和访问的网址"http://www.baidu.com/"。

Selenium 2 (webdriver) 代码:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
import unittest, time, re
class Sewd(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
self.verificationErrors = []
self.accept_next_alert = True
def test_sewd(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys("selenium grid")
driver.find_element_by_id("su").click()
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
unittest.main()

Selenium 2 (webdriver)的代码我们已经非常熟悉了,由于是直接调用浏览器的原生态接口驱动的,
所以我们并不需要指定代理电脑及端口。这就是 selenium 1 与 selenium 2 最本质的区别。

selenium 2 调用远程环境

在 selenium 1 中调用远程环境是非常简单的,由于其本身就运行于 selenium server 之上,只用在代
码中修改 主机地址及端口号即可。
在使用 selenium 2 由于其默认本地运行测试时是不需要 selenium server 的,但并不总是只执行本地
测试的脚本,有时候可能需要在本地调用远程的环境来执行测试,(比如:因为测试环境覆盖原因)此时就需要一个类似 selenium1 中的 RC 来承担这个任务,也就是 selenium2 中的 selenium-server。
selenium-server 支持接收远程脚本的调用命令,然后操作其宿主机上的浏览器来到远程执行测试的任务。当然 selenium-server 为了兼容 selenium1 的脚本,它同样也支持 selniumRC 所支持的功能(即能接收selenium1 的调用命令)。在本地调用远程机器执行测试的代码是这样的:

from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
driver = webdriver.Remote(
command_executor=’http://127.0.0.1:4444/wd/hub’, desired_capabilities=DesiredCapabilities.CHROME)
driver = webdriver.Remote(
command_executor=’http://127.0.0.1:4444/wd/hub’, 
desired_capabilities=DesiredCapabilities.OPERA)

第二节、selenium server 环境配置

由于 selenium e RC 是以代理的方式运行的,所以我们必须要借助于 selenium server 才能运行。
Selenium server 的运行又依赖于 java 环境,所以我们必须安装 java 环境并启动 selenium server 运行
selenium RC。
要想在 webdriver 中运行远程环境就必要要安装 selenium server,要想运行 selenium server 同样也需要安装 java 环境,下面跟笔者一起配置 selenium server 环境。

第一步、下载 java 及配置环境

下载地址:http://www.java.com/zh_CN/download/manual.jsp

小知识: java 环境分 JDK 和 JRE ,JDK 就是 Java Development Kit.简单的说 JDK 是面向开发人员使用的 SDK,它提供了 Java 的开发环境和运行环境。JRE 是 Java Runtime Enviroment 是指
Java 的运行环境,是面向 Java 程序的使用者,而不是开发者。

请选择适合本机的版本进行下载。以 windows 为例 java 环境为 exe 程序,安装默认路径即可。作者
默认安装在 C:\Program Files\Java\jdk1.7.0_45\路径下。 下面设置环境变量:
“我的电脑”右键菜单—>属性—>高级—>环境变量—>系统变量:

变量名:JAVA_HOME 变量值:C:\Program Files\Java\jdk1.7.0_45\
变量名:PATH
变量值:%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
变量名:CALSS_PATH
变量值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;

在 windows 命令提示符下输入 java 回车,果显示 java 用法及参数,说明环境配置成功。

第二步、下载运行 selenium server

下载地址:https://code.google.com/p/selenium/
在页面的左侧列表中找到 selenium-server-standalone-XXX.jar 进行下载。下载完成可以放到任意位置,直接在命令提示符下启动 selenium server:
C:\selenium> java -jar selenium-server-standalone-XXX.jar

在这里插入图片描述

运行脚本:

#coding=utf-8
import time
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
#指定运行主机与端口号
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4444/wd/hub',
desired_capabilities=DesiredCapabilities.CHROME)
driver.get("http://www.youdao.com")
driver.find_element_by_name("q").send_keys("hello")
driver.find_element_by_id("qb").click()
time.sleep(2)
driver.close()

查看 selenium server 日志就发现,selenium server 记录了客户端与服务器端交互的日志信息:
在这里插入图片描述

第三节、selenium Grid 工作原理

到此为止,其实还没有提到 selenium-grid,因为到目前为止我们还没有需求说同时覆盖多个平台和浏览器,而 selenium-grid 在这种情况下就会体现出其作用来。selenium-grid 是用于设计帮助我们进行分布式测试的工具,其整个结构是由一个 hub 节点和若干个代理节点组成。hub 用来管理各个代理节点的注册和状态信息,并且接受远程客户端代码的请求调用,然后把请求的命令再转发给代理节点来执行。使用selenium-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,若是同一台机器要启动多个 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

调用 Selenium-Grid 的基本结构图如下:
在这里插入图片描述

上面是使用 selenium-grid 的一种普通方式,仅仅使用了其支持的分布式执行的功能,即当你同时需
要测试用例比较多时,可以平行的执行这些用例进而缩短测试总耗时;除此之外,selenium-grid 还支持一种更友好的功能,即可以根据你用例中启动测试的类型来相应的把用例转发给符合匹配要求的测试代理。例如你的用例中指定了要在 Liunux 上 FireFox 的 17 版本进行测试,那么 selenium-grid 会自动匹配注册信息为 Linux、且安装了 FireFox17 的代理节点,如果匹配成功则转发测试请求,如果失败则拒绝请求。使用 selenium-grid 的远程兼容性测试的代码同上。其调用的基本结构图如下:

在这里插入图片描述

第四节、selenium Grid 应用

9.4.1、多浏览器执行用例

相信读者一定隐藏到心里一个遗留问题,我们在前面通过 python+webdriver 编写的测试脚本,只是在固定的某一款浏览器下运行,也许你已经尝试对浏览器进行参数化(webdriver.Firefox、webdriver.Chrome),
浏览器驱动并不是我们普通的数据,我们不能像对待普通数据一样对其进行参数化。
学到 selenium server 之后,我们似乎找到了一些眉目,下面就尝试将一段脚本在不同的浏览器下运行。
首先我们先来了解 webdriver 提供的 Remote 的格式。

driver = webdriver.Remote(
command_executor=’http://127.0.0.1:4444/wd/hub’,
desired_capabilities=DesiredCapabilities.CHROME)

http://127.0.0.1:4444/wd/hub’可以看作一个字符串,对其进行参数化没有什么困难。
那么 DesiredCapabilities.CHROME 里面包含了什么东西呢?

>>> from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
>>> p=DesiredCapabilities.CHROME
>>> print p
{'platform': 'ANY', 'browserName': 'chrome', 'version': '', 'javascriptEnabled': True}

我们将 DesiredCapabilities.CHROME 的内容打印输出,发现其本身是一个字典。
‘platform’: ‘ANY’ 平台默认可以是任何(window,MAC,android)。
‘browserName’: ‘chrome’ 浏览器名字是 chrome 。
‘version’: ‘’ 浏览器的版本默认为空。
‘javascriptEnabled’: True javascript 启动状态为 True
python webdriver API 提供了不同平台及浏览器的参数:
在这里插入图片描述

我们现在要做的是对 browserName 参数进行参数化,传入不同的浏览器,使脚本在不同的浏览器下运
行。要想运行脚本之前我们需要先启动 selenium server :

C:\selenium> java -jar selenium-server-standalone-2.39.0.jar

实现脚本如下:

#coding=utf-8
import time
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
#浏览器数组
lists=['chrome','internet explorer']
#通过不同的浏览器执行脚本
for browser in lists:
print browser
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4444/wd/hub',
desired_capabilities={'platform': 'ANY',
'browserName':browser,
'version': '',
'javascriptEnabled': True
})
driver.get("http://www.youdao.com")
driver.find_element_by_name("q").send_keys("hello")
driver.find_element_by_id("qb").click()
time.sleep(2)
driver.close()

在脚本的执行过程中,我们将看到,第一次启动 chrome 浏览器执行有道搜索的用例,第二次启动 IE
浏览器执行有道搜索的用例。
因为我们在读取 lists 每一条数据时打印,如果会看到如下的运行结果:

>>> ================================ RESTART ================================
>>>
chrome
internet explorer

在实际的过程中浏览器的数据会写在一个单独的文件中。请参考本书第四章第三节数据驱动(参数化)
的方式对浏览器进行参数化。

9.4.2、多节点执行用例

我们来先通过一台电脑演示启动多个节点,运行测试用例。通过 selneium Grid 工作原理一节我们了
解到要想启动多节点,前提是必须启动一个 Hub。
在本机打开两个命令提示符窗口分别启动一个 hub 和一个 node(节点)

C:\selenium>java -jar selenium-server-standalone-2.39.0.jar -role hub

C:\selenium>java -jar selenium-server-standalone-2.39.0.jar -role node -port 5555

如图
在这里插入图片描述

通过浏览器访问 gird 的控制台:
http://127.0.0.1:4444/grid/console
我们将在浏览器中看到,启动的节信息,如图 ; 从信息中可看到当前节点的 IP 和 OS 信息。
在这里插入图片描述

再次添加新的 node :

C:\selenium>java -jar selenium-server-standalone-2.39.0.jar -role node-port 5556

重新刷新 grid 的控制台。我们发现控制台又多出监控 5556 端口的 node:
在这里插入图片描述

下面修改脚本使其在不同的节点与浏览器上运行:
config.py

#coding=utf-8
def getconfig():
d={'http://127.0.0.1:5556/wd/hub':'chrome',
'http://127.0.0.1:4444/wd/hub':'internet explorer',
}
print "success read computer and browser!!"
return d

se_server.py

import time
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
import config #导入 config.py 文件
#通过 host,browser 来参数化脚本
for host,browser in config.getconfig().items():
print host
print browser
driver = webdriver.Remote(
command_executor=host,
desired_capabilities={'platform': 'ANY',
'browserName':browser,
'version': '',
'javascriptEnabled': True
})
driver.get("http://www.youdao.com")
driver.find_element_by_name("q").send_keys("hello")
driver.find_element_by_id("qb").click()
time.sleep(2)
driver.close()

运行结果:

>>> ================================ RESTART ================================
>>>
success read computer and browser!!
http://127.0.0.1:5555/wd/hub
internet explorer
http://127.0.0.1:4444/wd/hub
chrome

启动远程 node
我们目前启动的 Hub 与 node 都是在一台主机。那么要在其它主机启动 node 必须满足以下几个要求:

  • 本地 hub 主机与远程 node 主机之间可以相互 ping 通。
  • 远程主机必须安装运行脚本的浏览器及驱动(如,chrome 浏览器及 chromedriver.exe 驱动)
  • 远程主机必须安装 java 环境
  • 远程主机必须安装 selenium server

操作步骤如下:
启动本地 hub 主机(本地主机 IP 为:172.16.10.66):

C:\selenium>java -jar selenium-server-standalone-2.39.0.jar -role hub

启动远程主机(操作系统:ubuntu ,IP 地址:172.16.10.34):
远程主机启动 node 方式如下:

fnngj@fnngj-VirtualBox:~/selenium$ java -jarselenium-server-standalone-2.39.0ar -role node -port 5555-hub http://172.16.10.66:4444/grid/register

(设置的端口号为:5555 ,指向的 hub ip 为 172.16.10.66)
修改 config.py 文件,添加远程主机的操作。

#coding=utf-8
'''
'http://172.16.10.34:5555/wd/hub':'firefox',
添加远程主机信息,确保 ip 与端口号正确
'''
def getconfig():
d={'http://127.0.0.1:5556/wd/hub':'chrome',
'http://127.0.0.1:5555/wd/hub':'internet explorer',
'http://172.16.10.34:5555/wd/hub':'firefox',
}
print "success read computer and browser!!"
return d

现在程序不能在编辑器下运行,需要打开命令提示符号来运行 se_server.py 程序。
在这里插入图片描述

从运行结果看到,我们调用远程主机运行程序是 OK 的,能过远程主机也可以看到浏览器被成功启动
并执行相关操作。

9.4.3、分布式并行运行脚本

Selenium Grid 只是提供多系统、多浏览器的执行环境,Selenium Grid 本身并不提供并行的执行策略。
也就是说我们不可能简单地丢给 selenium grid 一个 test case 它就能并行地在不同的平台及浏览器下运行。如果您希望利用 Selenium Grid 的优势,那么您需要编写以并行模式运行的 Selenium 测试。

这里我们需要再次借助 python 的多线程技术来并行的运行脚本。

启动 selenium server

C:\selenium>java -jar selenium-server-standalone-2.39.0.jar

se_thread.py

#coding=utf-8
from threading import Thread
from selenium import webdriver
import time
#配置的 selenium server
def get_browser(caps):
return webdriver.Remote(
desired_capabilities=caps,
command_executor="http://127.0.0.1:4444/wd/hub"
)
#各平台配置信息
browsers = [
{ "platform":"WINDOWS", "browserName" : "firefox", "version" : '', "name" :
"FF" },
{ "platform":"WINDOWS", "browserName" : "internet explorer", "version" : '',
"name" : "IE" },
{ "platform":"WINDOWS", "browserName" : "chrome", "name" : "chrome" },]
#执行的脚本
browsers_waiting = []
def get_browser_and_wait(browser_data):
print "starting %s" % browser_data["name"]
browser = get_browser(browser_data)
browser.get("http://www.baidu.com")
browsers_waiting.append({ "data" : browser_data, "driver" : browser })
print "%s ready" % browser_data["name"]
while len(browsers_waiting) < len(browsers):
print "browser %s sending heartbeat while waiting" % browser_data["name"]
browser.get("http://www.baidu.com")
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
time.sleep(3)
#使用多线程运行脚本
thread_list = []
for i, browser in enumerate(browsers):
t = Thread(target=get_browser_and_wait, args=[browser])
thread_list.append(t)
t.start()
for t in thread_list:
t.join()
print "all browsers ready"
#循环关闭浏览器
for i, b in enumerate(browsers_waiting):
print "browser %s's title: %s" % (b["data"]["name"], b["driver"].title)
b["driver"].quit()

运行结果:

>>>
starting FFstarting IEstarting chrome
chrome ready
browser chrome sending heartbeat while waiting
IE ready
browser IE sending heartbeat while waiting
browser chrome sending heartbeat while waiting
FF ready
all browsers ready
browser chrome's title: selenium_百度搜索
browser internet explorer's title: selenium_百度搜索
browser fiefox's title: selenium_百度搜索

如果想使脚本在不同节点上运行需要对结果做配置,相关代码如下:

API_KEY = "KEY"
API_SECRET = "SECRET"
def get_browser(caps):
return webdriver.Remote(
desired_capabilities=caps,
command_executor="http://%s:%s@hub.testingbot.com/wd/hub" %
(API_KEY, API_SECRET)
)

总结:

本章介绍 selenium grid 版本问题,以及如何使用 selenium server 启动 hub 多个节点,如何操作脚本在不同平台,不同浏览器下运行。selenium grid 本身并没我们想象的那么神奇,要想顺利的使用的使用 selenium grid 的优势还需要读者做许多功课。

未完待续

关注我,每天持续更新软件测试小知识
软件测试打卡交流聚集地点我,每天都有教学直播【暗号:CSDN】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值