使用Docker解决自动化、性能测试的外部依赖

笔者目前在工作中,使用Python来进行项目的自动化、性能测试,但是在不同的环境下准备Python运行环境时遇到了不少的坑,随便列举一些:

1. Python版本的坑:

提到Python,最大的坑就是python2.x、python3.x共存的问题

比如在Ubuntu下部署接口测试的执行环境时,当你用pip安装相关的package,你有时完全搞不清楚这个包是安装在python2下还是在python3下;就算包的路径安装正确了,在执行测试代码时也有可能搞错python的解析器

大版本有坑,小版本也存在不少坑。比如在2.7.6之前的版本,用urlib3请求https的连接会出现ssl证书校验失败的问题;而当使用2.7.9这个版本时,Locust依赖的gevent对https的请求也会出现问题

2. Jenkins部署之坑:

在Jenkins部署时,我们用virtualenv来隔离系统侧python与任务侧的python,这样的好处就是每个任务中的python依赖都可以自定义,且不受干扰。

但带来了另外个问题:当不同任务的依赖相同时,会重复创建多份依赖;另外,在virtualenv环境下用pip安装依赖时,也会遇到各种权限问题,这里就不展开讲了。

3. 操作系统的坑:

OS的区别其实对接口测试影响还不大,主要是影响了性能测试。

笔者使用的Locust是基于gevent这个包,而gevent只有在linux环境下才能发挥最佳性能,所以之前笔者在OS X下发现locust产生的并发量很小主要是因为这个问题。

Docker化自动化、性能测试的实践

首先声明,这一段不是新手教程,只是些Docker实践的记录 :)

1. 安装Docker

Docker最佳宿主环境(可理解成你的操作系统)应该是Ubuntu,当使用这个操作系统时可以直接按照官方文档来进行: https://docs.docker.com/installation/ubuntulinux/

而在Windows、Mac OS X下,Docker其实无法直接安装,所以目前的策略是在这两个系统下启动一个Linux虚拟机,然后将Docker安装在这个虚拟机下

2. 构建Python运行环境

完成了Docker引擎的安装,然后开始创建一个最基础的Python运行环境

如果直接在ubuntu下用apt-get只能安装2.7.6版本的python,而这个版本存在一定的问题,所以这里我选用了最新的2.7.10版本,尝试从源码进行编译安装

创建名为Dockerfile的文件:

FROM ubuntu:14.04

MAINTAINER Jace Xu <jace@xuh.me>
ENV REFRESHED_AT 2015-06-22
ENV DEBIAN_FRONTEND noninteractive

RUN echo "Asia/Shanghai" > /etc/timezone && dpkg-reconfigure -f noninteractive tzdata

RUN apt-get -yqq update
RUN apt-get -yqq install wget curl xz-utils build-essential zlib1g-dev
RUN apt-get -yqq install libssl-dev
RUN apt-get purge -yqq python.*
ENV LANG C.UTF-8
RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys C01E1CAD5EA2C4F0B8E3571504C367C218ADD4FF
ENV PYTHON_VERSION 2.7.10

RUN set -x \
    && mkdir -p /usr/src/python \
    && curl -SL "https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tar.xz" -o python.tar.xz \
    && curl -SL "https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tar.xz.asc" -o python.tar.xz.asc \
    && gpg --verify python.tar.xz.asc \
    && tar -xJC /usr/src/python --strip-components=1 -f python.tar.xz \
    && rm python.tar.xz* \
    && cd /usr/src/python \
    && ./configure --enable-shared --enable-unicode=ucs4 \
    && make -j$(nproc) \
    && make install \
    && ldconfig \
    && curl -SL 'https://bootstrap.pypa.io/get-pip.py' | python2 \
    && pip install --no-cache-dir --upgrade pip \
    && find /usr/local \
        \( -type d -a -name test -o -name tests \) \
        -o \( -type f -a -name '*.pyc' -o -name '*.pyo' \) \
        -exec rm -rf '{}' + \
    && rm -rf /usr/src/python

CMD ["python2"]

Dockerfile其实跟shell脚本非常像,可以非常快速的理解

根据该Dockerfile构建一个镜像:

docker build -t="jacexh/python:2.7.10" .

请注意,上条指令最后有一个句点

这里我使用-t这个参数,给构建的镜像打了一个tag,解释下:

  • jacexh: 我在docker hub注册的帐号(可类比成git,这里即为github、gitlab的帐号)
  • python: docker hub上Repository名字(比如gitlab上shouqianba)
  • 2.7.10: 这个repository的标签(git的标签/分支均可)

所以,可以在docker hub上看到这个公开的镜像: https://registry.hub.docker.com/u/jacexh/python/

如果不想自己构建镜像,你可以直接用我发布的镜像:

docker pull jacexh/python:2.7.10

docker hub的使用是不是跟git很像?

3. 构建适用于接口测试的镜像

这里再创建一个Dockerfile:

FROM jacexh/python:2.7.10

MAINTAINER Jace Xu <jace@xuh.me>
ENV REFRESHED_AT 2015-06-22
ENV DEBIAN_FRONTEND noninteractive

RUN apt-get -yqq update

# 安装依赖
RUN apt-get install -yqq libffi-dev libzmq-dev libevent-dev libfreetype6-dev libxft-dev
RUN pip install -U requests simplejson xmlrunner paramiko locustio pyzmq mock redis pymongo==2.8
RUN pip install -U matplotlib numpy
RUN pip install -U selenium
RUN wget -qO- https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-linux-x86_64.tar.bz2 | tar jxv -C /opt
RUN ln -sf /opt/phantomjs-1.9.8-linux-x86_64/bin/phantomjs /usr/local/bin/phantomjs

EXPOSE 8089
mkdir -p /opt/workspace
WORKDIR /opt/workspace
ENTRYPOINT ["python"]

然后用build命令构建该镜像:

docker build -t="jacexh/testing" .

如果不想自己构建的化,直接下载docker hub上的镜像:

docker pull jacexh/testing

事实上:当你安装完docker后,直接执行上面一条命令即可,完全不用理会Step 2

4. 使用Docker镜像

上面提供的testing镜像只含有执行我们接口测试的python依赖,不含有我们的测试代码,因此我们需要把本地的代码挂载上去执行:

docker run -i -t --volume $PATH_SOURCECODE:/opt/workspace jacexh/testing runsuite.py
  • –volume: 将宿主环境的测试代码目录挂载到容器的/opt/workspace路径
  • runsuite.py: 自动化测试入口文件

5. Docker化对Selenium的影响

笔者的Web UI自动化测试项目中的selenium主要使用firefox作为web容器,而firefox又无法在cli环境下运行,因此我在这个镜像中使用PhantomJS作为替代,有用到selenium的代码应该做出一些改动:

像下面的代码: driver = webdriver.Firefox() 需要改成: driver = webdriver.PhantomJS()

另外PhantomJS解析出来的WebElement表达式与Firefox可能会有区别,这个在开发Web自动化测试的时候需要注意