笔者目前在工作中,使用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自动化测试的时候需要注意