在Docker容器内运行Selenium测试程序

目录

作者:杨冬 欢迎转载,也请保留这段声明。谢谢!
出处:https://andyyoung01.github.io/http://andyyoung01.16mb.com/

如果您的持续集成环境中包括针对浏览器运行的Selenium测试程序,要将这套环境容器化,则需要通过Docker容器运行图形化的程序,因为浏览器是一个图形化的程序。然而大多数的CI Server并没有图形化的环境,所以就需要使用xvfb程序来模拟一个图形化的环境。

如果想要在容器中运行图形化的程序,在启动容器的过程中,必须将用于显示图形窗口的X11使用的Unix socker挂载到容器的内部,而且需要指明你的图形程序需要显示在哪个显示号码($DISPLAY)上。可以通过以下命令检查您的环境是否符合条件:

1
2
3
4
~$ ls /tmp/.X11-unix/
X0
~$ echo $DISPLAY
:0

以上两个命令检查了您机器的环境(CentOs系统通常需要sudo yum groupinstall “GNOME Desktop”来安装X11图形界面)。现在想要将容器中的图形程序运行起来,并且在容器外部显示出来。
需要克服的首要问题就安全问题。X11提供了很多方法来认证容器中的程序来使用X11的Unix socket。首先我们通过.Xauthority文件来进行认证。默认情况下它应该存在于你的家目录中。它包含机器名以及每台机器用于连接的“secret cookie”。通过把容器的机器名指定为主机的机器名,就可以通过使用这个已经存在的认证文件,来连接到主机的X11的Unix socket上:

1
2
3
4
5
$ ls $HOME/.Xauthority
/home/myuser/.Xauthority
$ docker run -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix \
--hostname=$HOSTNAME -v $HOME/.Xauthority:/root/.Xauthority \
-it ubuntu:14.04 bash

第二种允许Docker连接到socket的方法是禁用所有的X提供的安全认证,这种方式存在安全问题。如果没有其它人可以连接到你的机器,这种方式也许可行,但你总是应该首先选择X认证文件的方式:

1
2
3
4
$ xhost +
access control disabled, clients can connect from any host
$ docker run -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix \
-it ubuntu:14.04 bash

上面的xhost +命令禁用了所有的到X的安全认证,然后下面的命令启动了Docker容器。你可以通过使用xhost -命令来重新启用到X的访问控制。
通过上面的方式启动容器后,可以验证一下是否可以在容器中运行X11程序:

1
2
3
root@db48929e89e0:/# apt-get update && apt-get install -y x11-apps
[...]
root@db48929e89e0:/# xeyes

如图所示,这启动了一个经典的测试X是否工作的程序:
{% asset_img 1.png “从容器中启动的xeyes程序”%}
下面开始进行Selenium的安装和运行。它是一个可以自动化浏览器动作的工具,主要用于模拟人员与浏览器的交互从而测试网站代码,它需要一个能将浏览器运行其中的图形显示环境。虽然它通常和Java一起使用,不过这里使用Python来进行交互动作,首先安装Selenium:

1
2
3
4
root@db48929e89e0:/# apt-get install -y python2.7 python-pip firefox
[...]
root@db48929e89e0:/# pip install selenium
[...]

然后通过下面的Python脚本来模拟一个动作:

access-github.py
1
2
3
4
5
6
from selenium import webdriver
b = webdriver.Firefox()
b.get('http://github.com')
searchbox=b.find_element_by_name('q')
searchbox.send_keys('docker-in-practice\n')

在容器中通过命令python access-github.py来运行上述脚本,会发现Firefox浏览器自动打开并且自动访问github网站,然后在其Search文本框中输入了docker-in-practice并且自动点击Search按钮。关于Selenium的使用细节不再详细描述,可以查询相关文档。
这里需要注意的是,我们在容器中运行了一个Python的脚本,并且看到脚本在容器中启动了FireFox的窗口,不过显示在了容器外部的主机桌面上。
上面的流程对于测试你写的脚本是非常有用的,但是怎样将其集成到CI管道中呢?通常CI服务器是没有图形显示环境的,所以我们就通过一个称为xvfb的工具来模拟X Server,作为程序的X环境。下面我们来看看这是怎样使用的。首先在镜像中安装xvfb,commit容器,将其tag为selenium:

1
2
3
4
root@db48929e89e0:/# apt-get install -y xvfb
[...]
root@db48929e89e0:/# exit
$ docker commit db48929e89e0 selenium

之后创建测试脚本:

1
2
3
4
5
6
7
8
9
10
11
$ cat> myscript.py << EOF
from selenium import webdriver
b = webdriver.Firefox()
b.get('http://github.com')
print 'Performing search...'
searchbox = b.find_element_by_name('q')
if searchbox.is_displayed():
searchbox.send_keys('docker-in-practice\n')
print 'Done!'
EOF

下面启动一个没有mount X11 socket的容器:

1
docker run --rm -v $(pwd):/mnt selenium sh -c "xvfb-run python /mnt/myscript.py"

上面的指令运行了一个完成后自动销毁的容器,它在一个虚拟的X Server下执行一个Python程序。经过测试Firefox浏览器可以在虚拟的X下正常启动运行,然而Selenium在xvfb的环境下似乎与真实的X Server有区别,可能还需要进一步调整代码来完成xvfb下的测试。如果不想进行调整的话,可以在整个容器中安装X环境来替代虚拟图形环境,这样会导致镜像的容量变大许多。