一说起持续集成,大家的固有印象就是Java。诚然,Java占了持续集成的半壁江山。可是,这是否意味着Python、Ruby、Node这样的脚本语言就跟持续集成扯不上关系呢?答案显然是否定的!其实不论什么语言,单元测试,代码覆盖率,以及静态代码检查这些软件工程的实践都是通用的。本文,我们将从一个实际的Pyghon项目,系统地学习一下在Python项目中该如何开展持续集成,包括使用nose框架做单元测试和覆盖率,以及使用pylint工具来检查代码质量。
文章分为上下两篇两部分,上篇讲述了如何在本地环境对一个Python项目做单元测试、覆盖率测试以及代码质量审查;下篇我们将把注意力从本地转移到Jenkins上来,系统地讲述一下如何将这些步骤跟Jenkins持续集成结合起来。
上篇——本地小试牛刀
创建目录结构
现在,我们从零开始,先在本地创建一个本文将要使用的Python项目。这里,我们的工作目录是~/dev/project1,在该工作目录下,我们创建了project1文件夹用来放置我们的Python源代码;接着,我们又创建了tests文件夹用来放置单元测试的测试用例文件。最后,我们还分别为这两个文件夹添加init.py文件,这样,这两个文件夹就能被Python识别为package包了。
mkdir -p ~/dev/project1
cd project1
git init
mkdir project1
touch project1/__init__.py
mkdir tests
touch tests/__init__.py
养成经常commit的好习惯,到这里,我们先运行git commit提交当前的工作。
git add .
git commit -m "添加2个空的Python包: project1 and tests"
编写项目代码
下一步,我们来编写Python项目代码,为了方便,我们的项目就只有一个authentication.py文件,并且该文件只有一个login(username,password)的登陆方法和一个logout()登出方法。
vim project1/authentication.py
编写测试用例
紧接着,我们来编写tests/authentication_tests.py测试用例文件,为项目代码中的login()方法添加如下3个测试用例——1个登陆成功的用例,1个登陆失败的用例,以及1个I/O异常的用例。这里,我们故意不为logout()方法设计测试用例,以便后面能较明显地从覆盖率报表中看出我们的测试覆盖率不够的问题。我们在测试文件中使用了Python的mock模块来构造测试数据,这在Python开发中也是比较常见的一种测试方法,关于Python的mock模块详细用法,读者可以看文末的参考资料,这里不作展开。
vim tests/authentication_tests.py
本地自测
其实,截止到现在,我们已经足够在本地进行自测了。我们来执行下nosetests命令,可以看到,nosetests为我们执行了3个测试用例,并且我们项目的代码覆盖率为87%。
nosetests --with-coverage --cover-package=project1
那我们项目的代码质量写得如何呢?我们来执行一下pylint命令,审查一下我们的代码质量:
pylint -r n project1
可以看出,pylint工具为我们检查出了4处代码不规范的地方,其中两处C是Convertion相关的,表示违反了Python的编码风格;还有两处W是指违反了Python语言相关而给出的警告。[我会告诉你这是我故意留的么?] 当然,你如果希望看到更多更详细的输出,那也是可以的,执行:
pylint -r y project1
[图太多,就不多截啦!]
推送到远程仓库
到目前为止,本地的Python项目和测试用例都已经写完了。老规矩,我们先提交工作内容,并且推送至远程的Git仓库。
git add .
git commit -m "添加项目文件以及测试文件"
git config user.name "hzchenshibin"
git config user.email "hzchenshibin@corp.netease.com"
git remote add origin git remote add origin https://git.hz.netease.com/git/hzchenshibin/python-jenkins.git
git push -u origin master
下篇——傍上Jenkins的大腿
在上篇中,我们已经在本地把Python项目的单元测试,代码覆盖率,代码静态审查等这些准备工作都完成了。那在这篇中,我们来具体看一下,应该怎么跟高大上的Jenkins集成起来,傍上持续集成的大腿。读者先不要着急,下面我们就一步一步来揭开谜底。
第一步:节点机环境准备
显而易见,在上篇中,我们用到了python中的python-mock,python-nose,python-coverage以及pylint这些包,所以,在配置Jenkins的Job之前,请确保你的节点机上面已经正确安装了这些Python包:
- python-mock: 用来生成测试数据。
- python-nose: Python单元测试包。
- python-coverage: Python代码覆盖率包。
- pylint: Python静态代码审查包。
这些包都可以在它们的官网或者通过包管理工具来安装。以Ubuntu系统为例,可以通过sudo apt-get来安装;如果是Mac或者其他Linux系统,也可以通过Python自己的包管理工具easy-install或者pip来安装,这里不做详细展开,读者可以从文章末尾的参考材料获取更多的知识。
Ubuntu系统上安装所需要的Python包的实例:
sudo apt-get install python-mock python-nose python-coverage pylint
第二步:用到的Jenkins插件
Jenkins拥有丰富的第三方插件,可以用来帮助我们完成各种个样的雪球。下列是本文中用到的几个插件:
- Git Plugin:用来从Gitbucket源代码库拉取代码
- Junit Plugin: 用来展示nose框架生成的单元测试报表
- Cobertura Plugin:用来展示Python代码测试覆盖率报表
- Violations:用来展示Python静态代码审查报表,支持pylint、jslint等
第三步:Jenkins的Job配置
SCM代码仓库配置 将我们在上篇中推送的远程仓库的URL配置在这里,这样,Jenkins就可以从该远程仓库拉取我们之前推送的项目代码:
节点机选择 选择我们上文配置好的节点机
添加构建步骤 Add Buid Step-->Execute Shell --with-xunit --all-modules --traverse-namespace --with-coverage这些都是nose框架自带的参数,详细用法可以自行参考其官方文档[参考材料1]。 python -m coverage xml命令用来将nose框架生成的.coverage文件转换成Jenkins能够理解的xml格式。
设置单元测试报表展示 Add post-build action-->Public Junit test result report,在Test report XMLs这一栏填写上一步构建生成的单元测试xml文件:
设置代码覆盖率报表展示 Add post-build action-->Public Cobertura Coverage Report,在Cobertura xml report pattern这一栏填写上一步构建生成的覆盖率xml文件:
设置静态代码审查报表展示 Add post-build action-->Reports Violations,在pylint这一栏,填写上一步生成的代码质量审查输出文件:
提交构建 点击左侧的”Build Now“,等待构建完成,打开Console Output查看构建日志:
当然,我们做了这么多工作,想看的可不是这些字符的文本报表。上文中我们已经配置了的各种报表插件,那么现在已经到了展现威力的时候了。我们分别来看一下Jenkins给我们生成的单元测试报表,代码覆盖率报表,以及Pylint生成的代码质量报表都长啥样:
单元测试报表
代码覆盖率报表 点进源码,可以看到详细的覆盖率情况,绿色表示已经覆盖到了,红色表示未被测试用例覆盖到的代码 :
代码质量审查报表
参考材料
- nosetests官方文档 [http://nose.readthedocs.org/en/latest/]
- pylint官方文档 [http://www.pylint.org/]
- pymock官方文档 [http://theblobshop.com/pymock/]
- Jenkins的Violation插件文档 [https://wiki.jenkins-ci.org/display/JENKINS/Violations]
- Automated python unit testing, code coverage and code quality analysis with Jenkins [http://bhfsteve.blogspot.hk/2012/04/automated-python-unit-testing-code.html]
Comments !