自动化工具 docker+selenium 搭建和踩坑记录

Jerry li · May 08, 2018 · Last by AItestwork replied at July 05, 2018 · 3422 hits

前记:Python+flask+bootstrap+macaca 搭建 web/ Android 自动化测试管理平台 https://testerhome.com/topics/11183
使用 python + flask 搭建的 selenium web 自动化测试平台已经运行一段时间。 一直以来都是需要在自己的 windows 机上启动 selenium server 作为运行的媒介,不是很方便。于是考虑使用 docker 来作为运行用例的平台。

安装步骤:

1. 安装 docker。

首先打算在测试的 linux 服务器上搭建,无奈服务器 linux 版本太低(上面的部署的服务还挺多的,不想冒升级内核版本的风险),尝试了很多次都无法愉快地把 docker 跑起来,最终选择先在 Windows 服务器下先尝试搭起来。 具体安装步骤网上很多,这里就不多说了。

2. 拉取所需的 docker 镜像。

目前使用到两个镜像:
docker pull selenium/hub
docker pull selenium/node-chrome

3. 启动对应 docker 镜像。

按 selenium docker 官方 GitHub 上的推荐方式启动如下:
docker network create grid
docker run -d -p 4444:4444 --net grid --name selenium-hub selenium/hub
docker run -d --net grid -e HUB_HOST=selenium-hub -v /dev/shm:/dev/shm selenium/node-chrome

服务顺利起来了,可以查看到对应 selenium 节点:
http://192.168.99.100:4444/grid/console#

4. 跑一下测试脚本,可以正常调用服务进行测试:

from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
driver = webdriver.Remote(command_executor='http://192.168.99.100:4444/wd/hub',
                              desired_capabilities = chrome_options.to_capabilities())
driver.get('http://www.baidu.com/')
driver.find_element_by_id("kw").send_keys("docker selenium test")
driver.find_element_by_id("su").click()
driver.get_screenshot_as_file("c://img1.png")
driver.quit()

踩坑记

1. 外网访问 docker 里的 selenium 服务。

设计的架构里,测试平台将调用对应的 selenium server 服务发起测试。但现在 docker 只能在 Windows 服务器内访问,因此需要把对应的端口转发出去。
步骤:

1.1 把 selenium docker 镜像对应的 ip 192.168.99.100,端口为 4444 的 docker 服务转发到本地(对应的局域网 ip 为 172.16.100.1):

cmd 执行:
netsh interface portproxy add v4tov4 listenport=4444 listenaddress=172.16.100.1 connectport=4444 connectaddress=192.168.99.100

1.2 Windows 防火墙中添加端口 4444 的对应转发规则(防火墙》高级设置 ,分别添加入站规则和出站规则)

这样,局域网的服务器就可以通过 172.16.100.1:4444 调用 selenium hub 的服务了。

2. 窗口最大化失败

在脚本中对浏览器进行最大化操作:
driver.maximize_window()

这个命令一向运行是没问题的,但是在 docker 中却报错如下:
Message: unknown error: failed to change window state to maximized, current state is normal

查了一下,说是 selenium 的 bug。 找了一下,没有合适的解决方案,粗暴解决如下:

try:
    driver.maximize_window()
except WebDriverException as e:
    log.log().logger.info(e)
    driver.set_window_size(1920, 1080)  #如果最大化失败,设置窗口大小为 1920*1080

3. chrome option 不生效。

因为部分用例需要模拟移动设备,或设置浏览器为英文,所以使用 chrome option 进行设置。 原来的初始化脚本如下:

desired_caps_web = webdriver.DesiredCapabilities.CHROME
deviceList = ['Galaxy S5', 'Nexus 5X', 'Nexus 6P', 'iPhone 6', 'iPhone 6 Plus', 'iPad', 'iPad Pro']
if devicename!='' :
    if devicename not in deviceList:
        devicename = deviceList[2]
    chrome_option = {
        'args': ['lang=en_US','start-maximized'],
        'extensions': [], 'mobileEmulation': {'deviceName': ''}

    }
    chrome_option['mobileEmulation']['deviceName'] = devicename
else:
    chrome_option = {
        'args': ['lang=en_US','--start-maximized'],
        'extensions': []
    }
desired_caps_web['goog:chromeOptions']=chrome_option
log.log().logger.info(desired_caps_web)
driver = webdriver.remote.webdriver.WebDriver(command_executor=server_url,desired_capabilities=desired_caps_web)

但同样,之前一直正常运行的脚本,到 docker 里不起作用。
看下 docker selenium node 节点的 log ,发现打印了如下信息:

Capabilities are: Capabilities {browserName: chrome, chromeOptions: {args: [lang=zh_CN.UTF-8],  mobileEmulation: {deviceName: iPhone 6}}, goog:chromeOptions: {}, javascriptEnabled: true, version: }

多了个 goog:chromeOptions {} 的配置项是怎么回事?

认真看下,Capabilities 里我设置的 chromeOptions 已经正确传进来了,但是后面的 goog:chromeOptions: {} 似乎覆盖了对应的配置。
尝试下把脚本里的参数名称从 “chromeOptions ” 改为 “goog:chromeOptions” ,奇迹出现了:

Capabilities are: Capabilities {browserName: chrome, goog:chromeOptions: {args: [lang=zh_CN.UTF-8], mobileEmulation: {deviceName: iPhone 6}}, javascriptEnabled: true, version: }

脚本也能正常运行了,对应的浏览器语言、移动设备模拟设置也已生效!

于是修改对应脚本为:

desired_caps_web['goog:chromeOptions']=chrome_option

问题解决!

至此,脚本可以愉快的跑起来了!

共收到 7 条回复 时间 点赞
Jerry li #1 · May 09, 2018 Author

今天补充调用 Firefox 节点时遇到的两个问题:

1. 找不到对应的 Capabilities :

Error forwarding the new session cannot find : Capabilities {browserName: firefox, javascriptEnabled: true, marionette: false, version: }

对比下 webdriver.DesiredCapabilities.FIREFOX 和 webdriver.DesiredCapabilities.CHROME 的参数结构,发现 Firefox 中多了一个参数 marionette(默认是 false)。
搜索一下,是 Firefox 新的驱动,手动改为 true ,不再报这个错误。

2. 连接 Firefox 节点后,selenium 报错 KeyError: 'sessionId'

搜索一下,说是 selenium 版本的问题。升级到最新版本后,问题解决。

实际上升级版本后, DesiredCapabilities.FIREFOX 的 marionette 默认已改为 True, 问题 1 其实也解决了:

结论: 遇到不明白的报错可以试下先升级版本,这样可以避开一些旧版本的坑。

最大化是不是可以试试 chrome option 里--start-maximized?

Jerry li #3 · May 10, 2018 Author
mypchas6fans 回复

试过了,不起作用

Jerry li #4 · May 10, 2018 Author

更新 2 :
更新 selenium 版本后, 最大化也正常了:
driver.maximize_window()

Jerry li #6 · May 10, 2018 Author
苏公子 回复

👍 赞!

Author only
需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up