宅鳥所使用的server為Ubuntu
要實作在jenkins中實作php的自動化測試,首先需要Jenkins伺服器上安裝php測試架構,php的測試架構很多,在這裡我們選擇 PHPUnit Framework.
PHPUnit的安裝很簡單:
1
<code>sudo</code> <code>apt-get </code><code>install</code> <code>phpunit</code>
如果出現如下錯誤:
2
<code>PHP Warning: require_once(PHP</code><code>/CodeCoverage/Filter</code><code>.php): failed to </code><code>open</code> <code>stream: No such </code><code>file</code> <code>or directory </code><code>in</code> <code>/usr/bin/phpunit</code> <code>on line 39</code>
<code>PHP Fatal error: require_once(): Failed opening required </code><code>'PHP/CodeCoverage/Filter.php'</code> <code>(include_path=</code><code>'.:/usr/share/php:/usr/share/pear'</code><code>) </code><code>in</code> <code>/usr/bin/phpunit</code> <code>on line 39</code>
可以通過下面方法安裝:
3
4
5
6
7
8
9
<code>sudo</code> <code>pear channel-discover pear.phpunit.de</code>
<code>sudo</code> <code>pear channel-discover pear.symfony-project.com</code>
<code>sudo</code> <code>pear channel-discover components.ez.no</code>
<code>sudo</code> <code>pear channel-discover pear.symfony.com</code>
<code>sudo</code> <code>pear update-channels</code>
<code>sudo</code> <code>pear upgrade-all</code>
<code>sudo</code> <code>pear </code><code>install</code> <code>pear.symfony.com</code><code>/Yaml</code>
<code>sudo</code> <code>pear </code><code>install</code> <code>--alldeps phpunit</code><code>/PHPUnit</code>
<code>sudo</code> <code>pear </code><code>install</code> <code>--force --alldeps phpunit</code><code>/PHPUnit</code>
安裝後執行phpunit --version 傳回版本資訊。表示安裝成功。
<code>root@dop-kvm-2:</code><code># phpunit --version</code>
<code>PHPUnit 3.7.28 by Sebastian Bergmann.</code>
下面我們開始給Jenkins一些插件:
Subversion/Git:用于內建項目版本控制軟體,根據需要選擇(在上篇博文已安裝使用)
Phing/Ant:使用Phing或Apache Ant 對PHP項目做自動化建構
CheckStyle:使用PHP CodeSniffer進行代碼風格檢查的工具。用于檢查PHP代碼是否有違反一組預先設定好的編碼标準的一個PEAR包,内置了ZEND,PEAR的編碼風格規則
Clover PHP:使用phpunit進行單元測試的工具,可以被xdebug擴充用來生成代碼覆寫率報告,并且可以與phing內建來自動測試,還可以和Selenium整合來完成大型自動化內建測試
DRY:使用PHPCPD(php copy paste detector)來發現項目中的重複代碼
HTML Publisher:用來釋出phpunit代碼覆寫率報告
JDepend:使用PHP Depend分析php中靜态代碼,用來檢查項目中的代碼規模和複雜程度
Plot:使用phploc來統計php項目規模大小的工具,可以統計php的項目代碼行數
PMD:使用phpmd(php mess dector),對基于pdepend的結果進行分析,一旦項目超過了pdepend中各具體名額的規定,将發出警告資訊.
Violations:按照代碼缺陷嚴重性集中顯示pwd靜态代碼分析的結果
xUnit:使用JUnit的格式來輸出phpunit的日志檔案
注意這些插件是jenkins為php項目所提供的一些插件,但并不是必須的,是以宅鳥隻把最值得大家關注的怎麼自動化測試、打包和釋出來給大家講解。
先給出項目的目錄結構:
<code>root@dop-kvm-2:</code><code>/home/jenkins/api</code><code># tree</code>
<code>.</code>
<code>├── aa.php</code>
<code>├── build.xml</code>
<code>├── create.php</code>
<code>└── </code><code>test</code>
<code> </code><code>├── DemoTest.php</code>
<code> </code><code>└── FunctionTest.php</code>
<code>1 directory, 5 files</code>
注意:
aa.php、create.php是項目的程式檔案
test目錄下的DemoTest.php和FunxtionTest.php是項目的測試檔案
build.xml是jenkins持續內建測試打包部署的調用檔案
首先給出項目需要的build.xml檔案:
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<code><?</code><code>xml</code> <code>version</code><code>=</code><code>"1.0"</code> <code>encoding</code><code>=</code><code>"UTF-8"</code><code>?></code>
<code><</code><code>project</code> <code>name</code><code>=</code><code>"api"</code> <code>default</code><code>=</code><code>"build"</code><code>></code>
<code> </code><code><</code><code>target</code> <code>name</code><code>=</code><code>"build"</code> <code>depends</code><code>=</code><code>"make_runtime,phpcs-ci,phploc,pdepend,phpcb,phpunit,phpdox,phpcpd"</code><code>/></code>
<code> </code><code><</code><code>property</code> <code>name</code><code>=</code><code>"version-m"</code> <code>value</code><code>=</code><code>"1.1"</code> <code>/></code>
<code> </code><code><</code><code>property</code> <code>name</code><code>=</code><code>"version"</code> <code>value</code><code>=</code><code>"1.1.0"</code> <code>/></code>
<code> </code><code><</code><code>property</code> <code>name</code><code>=</code><code>"stability"</code> <code>value</code><code>=</code><code>"stable"</code> <code>/></code>
<code> </code><code><</code><code>property</code> <code>name</code><code>=</code><code>"releasenotes"</code> <code>value</code><code>=</code><code>""</code> <code>/></code>
<code> </code><code><</code><code>property</code> <code>name</code><code>=</code><code>"tarfile"</code> <code>value</code><code>=</code><code>"${phing.project.name}.${buildnumber}.${buildid}.tar.gz"</code> <code>/></code>
<code> </code><code><</code><code>property</code> <code>name</code><code>=</code><code>"pkgfile"</code> <code>value</code><code>=</code><code>"${phing.project.name}.${version}.tgz"</code> <code>/></code>
<code> </code><code><</code><code>property</code> <code>name</code><code>=</code><code>"distfile"</code> <code>value</code><code>=</code><code>"dist/${tarfile}"</code> <code>/></code>
<code> </code><code><</code><code>property</code> <code>name</code><code>=</code><code>"tests.dir"</code> <code>value</code><code>=</code><code>"test"</code> <code>/></code>
<code> </code><code><</code><code>fileset</code> <code>id</code><code>=</code><code>"api.tar.gz"</code> <code>dir</code><code>=</code><code>"."</code><code>></code>
<code> </code><code><</code><code>include</code> <code>name</code><code>=</code><code>"test/**"</code><code>/></code>
<code> </code><code><</code><code>include</code> <code>name</code><code>=</code><code>"*.php"</code><code>/></code>
<code> </code><code><</code><code>include</code> <code>name</code><code>=</code><code>"*.xml"</code><code>/></code>
<code> </code><code></</code><code>fileset</code><code>></code>
<code> </code><code><</code><code>target</code> <code>name</code><code>=</code><code>"make_runtime"</code><code>></code>
<code> </code><code><</code><code>mkdir</code> <code>dir</code><code>=</code><code>"${project.basedir}/Runtime"</code> <code>/></code>
<code> </code><code><</code><code>mkdir</code> <code>dir</code><code>=</code><code>"${project.basedir}/build/logs"</code> <code>/></code>
<code> </code><code><</code><code>mkdir</code> <code>dir</code><code>=</code><code>"${project.basedir}/build/pdepend"</code> <code>/></code>
<code> </code><code><</code><code>mkdir</code> <code>dir</code><code>=</code><code>"${project.basedir}/build/code-browser"</code> <code>/></code>
<code> </code><code></</code><code>target</code><code>></code>
<code> </code><code><</code><code>target</code> <code>name</code><code>=</code><code>"phpcs"</code> <code>description</code><code>=</code><code>"Find coding standard violations using PHP_CodeSniffer"</code><code>></code>
<code> </code><code><</code><code>exec</code> <code>executable</code><code>=</code><code>"phpcs"</code><code>></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"--standard=${project.basedir}/build/phpcs.xml"</code> <code>/></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"--ignore=autoload.php"</code> <code>/></code>
<code> </code><code><</code><code>arg</code> <code>path</code><code>=</code><code>"${project.basedir}/"</code> <code>/></code>
<code> </code><code></</code><code>exec</code><code>></code>
<code> </code><code><</code><code>target</code> <code>name</code><code>=</code><code>"phpcs-ci"</code> <code>description</code><code>=</code><code>"Find coding standard violations using PHP_CodeSniffer"</code><code>></code>
<code> </code><code><</code><code>exec</code> <code>executable</code><code>=</code><code>"phpcs"</code> <code>output</code><code>=</code><code>"${project.basedir}/build/build.log"</code><code>></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"--report=checkstyle"</code> <code>/></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"--report-file=${project.basedir}/build/logs/checkstyle.xml"</code> <code>/></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"--ignore="</code> <code>/></code>
<code> </code>
<code> </code><code><</code><code>target</code> <code>name</code><code>=</code><code>"phploc"</code> <code>description</code><code>=</code><code>"Measure project size using PHPLOC"</code><code>></code>
<code> </code><code><</code><code>exec</code> <code>executable</code><code>=</code><code>"phploc"</code><code>></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"--log-csv"</code> <code>/></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"${project.basedir}/build/logs/phploc.csv"</code><code>/></code>
<code> </code><code><</code><code>arg</code> <code>path</code><code>=</code><code>"${project.basedir}/"</code><code>/></code>
<code> </code><code><</code><code>target</code> <code>name</code><code>=</code><code>"pdepend"</code> <code>description</code><code>=</code><code>"Calculate software metrics using PHP_Depend"</code><code>></code>
<code> </code><code><</code><code>exec</code> <code>executable</code><code>=</code><code>"pdepend"</code><code>></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"--jdepend-xml=${project.basedir}/build/logs/jdepend.xml"</code><code>/></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"--jdepend-chart=${project.basedir}/build/pdepend/dependencies.svg"</code><code>/></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"--overview-pyramid=${project.basedir}/build/pdepend/overview-pyramid.svg"</code><code>/></code>
<code> </code><code><</code><code>target</code> <code>name</code><code>=</code><code>"phpmd"</code> <code>description</code><code>=</code><code>"Perform project mess detection using PHPMD"</code><code>></code>
<code> </code><code><</code><code>exec</code> <code>executable</code><code>=</code><code>"phpmd"</code><code>></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"text"</code><code>/></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"${project.basedir}/build/phpmd.xml"</code><code>/></code>
<code> </code><code><</code><code>target</code> <code>name</code><code>=</code><code>"phpmd-ci"</code> <code>description</code><code>=</code><code>"Perform project mess detection using PHPMD"</code><code>></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"xml"</code><code>/></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"--reportfile"</code><code>/></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"${project.basedir}/build/logs/pmd.xml"</code><code>/></code>
<code> </code><code><</code><code>target</code> <code>name</code><code>=</code><code>"phpcpd"</code> <code>description</code><code>=</code><code>"Find duplicate code using PHPCPD"</code><code>></code>
<code> </code><code><</code><code>exec</code> <code>executable</code><code>=</code><code>"phpcpd"</code><code>></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"--log-pmd"</code><code>/></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"${project.basedir}/build/logs/pmd-cpd.xml"</code><code>/></code>
<code> </code><code><</code><code>target</code> <code>name</code><code>=</code><code>"phpdox"</code> <code>description</code><code>=</code><code>"Generate API documentation using phpDox"</code><code>></code>
<code> </code><code><</code><code>exec</code> <code>executable</code><code>=</code><code>"phpdox"</code><code>/></code>
<code> </code><code><</code><code>target</code> <code>name</code><code>=</code><code>"phpunit"</code> <code>description</code><code>=</code><code>"Run unit tests with PHPUnit"</code><code>></code>
<code> </code><code><</code><code>exec</code> <code>executable</code><code>=</code><code>"phpunit"</code> <code>/></code>
<code> </code><code><</code><code>target</code> <code>name</code><code>=</code><code>"test"</code> <code>description</code><code>=</code><code>"Run PHPUnit tests"</code><code>></code>
<code> </code><code><</code><code>phpunit</code> <code>haltonerror</code><code>=</code><code>"true"</code> <code>haltonfailure</code><code>=</code><code>"true"</code> <code>printsummary</code><code>=</code><code>"true"</code><code>></code>
<code> </code><code><</code><code>batchtest</code><code>></code>
<code> </code><code><</code><code>fileset</code> <code>dir</code><code>=</code><code>"${tests.dir}"</code><code>></code>
<code> </code><code><</code><code>include</code> <code>name</code><code>=</code><code>"**/*Test.php"</code> <code>/></code>
<code> </code><code></</code><code>fileset</code><code>></code>
<code> </code><code></</code><code>batchtest</code><code>></code>
<code> </code><code></</code><code>phpunit</code><code>></code>
<code> </code><code><</code><code>target</code> <code>name</code><code>=</code><code>"phpcb"</code> <code>description</code><code>=</code><code>"Aggregate tool output with PHP_CodeBrowser"</code><code>></code>
<code> </code><code><</code><code>exec</code> <code>executable</code><code>=</code><code>"phpcb"</code><code>></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"--log"</code><code>/></code>
<code> </code><code><</code><code>arg</code> <code>path</code><code>=</code><code>"${project.basedir}/build/logs"</code><code>/></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"--source"</code><code>/></code>
<code> </code><code><</code><code>arg</code> <code>value</code><code>=</code><code>"--output"</code><code>/></code>
<code> </code><code><</code><code>arg</code> <code>path</code><code>=</code><code>"${project.basedir}/build/code-browser"</code><code>/></code>
<code> </code><code><</code><code>target</code> <code>name</code><code>=</code><code>"check"</code> <code>description</code><code>=</code><code>"Check variables"</code> <code>></code>
<code> </code><code><</code><code>fail</code> <code>unless</code><code>=</code><code>"version"</code> <code>message</code><code>=</code><code>"Version not defined!"</code> <code>/></code>
<code> </code><code><</code><code>fail</code> <code>unless</code><code>=</code><code>"buildnumber"</code> <code>message</code><code>=</code><code>"buildnumber not defined!"</code> <code>/></code>
<code> </code><code><</code><code>fail</code> <code>unless</code><code>=</code><code>"buildid"</code> <code>message</code><code>=</code><code>"buildid not defined!"</code> <code>/></code>
<code> </code><code><</code><code>delete</code> <code>dir</code><code>=</code><code>"dist"</code> <code>failonerror</code><code>=</code><code>"false"</code> <code>/></code>
<code> </code><code><</code><code>mkdir</code> <code>dir</code><code>=</code><code>"dist"</code> <code>/></code>
<code> </code><code><</code><code>target</code> <code>name</code><code>=</code><code>"tar"</code> <code>depends</code><code>=</code><code>"check"</code> <code>description</code><code>=</code><code>"Create tar file for release"</code><code>></code>
<code> </code><code><</code><code>echo</code> <code>msg</code><code>=</code><code>"Creating distribution tar for ${phing.project.name} ${version}"</code><code>/></code>
<code> </code><code><</code><code>delete</code> <code>file</code><code>=</code><code>"${distfile}"</code> <code>failonerror</code><code>=</code><code>"false"</code><code>/></code>
<code> </code><code><</code><code>tar</code> <code>destfile</code><code>=</code><code>"${distfile}"</code> <code>compression</code><code>=</code><code>"gzip"</code><code>></code>
<code> </code><code><</code><code>fileset</code> <code>refid</code><code>=</code><code>"api.tar.gz"</code><code>/></code>
<code> </code><code></</code><code>tar</code><code>></code>
<code></</code><code>project</code><code>></code>
閱讀build.xml後,大家可以了解一下内容:
項目名稱、版本、打後的包名稱:
打包時包括的檔案和檔案夾:這裡還可以使用exclude排除檔案和檔案夾:
<code><</code><code>fileset</code> <code>id</code><code>=</code><code>"api.tar.gz"</code> <code>dir</code><code>=</code><code>"."</code><code>></code>
<code> </code><code><</code><code>include</code> <code>name</code><code>=</code><code>"test/**"</code><code>/></code>
<code> </code><code><</code><code>include</code> <code>name</code><code>=</code><code>"*.php"</code><code>/></code>
<code> </code><code><</code><code>include</code> <code>name</code><code>=</code><code>"*.xml"</code><code>/></code>
<code> </code><code></</code><code>fileset</code><code>></code>
測試檔案所在位址:
<code><</code><code>target</code> <code>name</code><code>=</code><code>"phpunit"</code> <code>description</code><code>=</code><code>"Run unit tests with PHPUnit"</code><code>></code>
了解這些後,我們開始在jenkins中建立autoTestTarAndPublish項目,選擇:建構一個自由風格的軟體項目:
并且指定好代碼庫:如圖所示
<a href="http://blog.51cto.com/attachment/201312/172124575.jpg" target="_blank"></a>
然後再 增加建構步驟->Invoke Phing targets:
增加兩個 target: test,tar 分别與build.xml中的test,tar名稱相對應
<a href="http://blog.51cto.com/attachment/201312/172650946.jpg" target="_blank"></a>
給tar加上參數:
<a href="http://blog.51cto.com/attachment/201312/172622637.jpg" target="_blank"></a>
然後在左邊主菜單: 系統管理->系統設定->Publish over SSH 下添加主機:(這裡宅鳥設定使用ssh免密碼登陸)需要設定成從jenkins到要釋出的web伺服器的無密碼登陸
如圖設定:
<a href="http://blog.51cto.com/attachment/201312/175130605.jpg" target="_blank"></a>
這裡添加設定的主機名是:134
接下來我們就可以設定部署工作了:
<a href="http://blog.51cto.com/attachment/201312/174009766.jpg" target="_blank"></a>
然後在出現的SSH Publishers中選擇要釋出的主機:
并填寫打封包件位址,釋出到遠端server位址資訊,并在Exec command文本框中填寫解壓等shell腳本:
詳情見圖:
<a href="http://blog.51cto.com/attachment/201312/175817788.jpg" target="_blank"></a>
此項設定完畢後,就可以釋出php項目到134伺服器上了:
最後檔案釋出包的存檔工作:
增加建構後操作步驟:
<a href="http://blog.51cto.com/attachment/201312/180033526.jpg" target="_blank"></a>
填寫dist/*.tar.gz
<a href="http://blog.51cto.com/attachment/201312/180210215.jpg" target="_blank"></a>
至此配置完畢後,點選 儲存 按鈕.我們就可以釋出程式到指定伺服器134上了.
來看一下釋出結果:
回到項目左側點選:立即建構:可以看到建構進度條,結束後可以在控制台看到輸出結果:
<a href="http://blog.51cto.com/attachment/201312/085434850.jpg" target="_blank"></a>
我們來到134上看:
<a href="http://blog.51cto.com/attachment/201312/180805428.jpg" target="_blank"></a>
至此釋出完畢.
此時我們檢視一下test/DemoTest.php檔案内容:
<code><?php</code>
<code>class</code> <code>DemoTest </code><code>extends</code> <code>PHPUnit_Framework_TestCase {</code>
<code> </code><code>public</code> <code>function</code> <code>testPass() {</code>
<code> </code><code>$this</code><code>->assertTrue(true);</code>
<code> </code><code>}</code>
<code> </code><code>public</code> <code>function</code> <code>testFail() {</code>
<code> </code><code>$this</code><code>->assertFalse(false);</code>
<code>}</code>
<code>?></code>
我們把 testFail()改成下面:
<code> </code><code>$this</code><code>->assertTrue(false);</code>
<code></code><code>$this</code><code>->assertTrue(false);</code>
這個是錯誤的斷定:
送出檔案後再次建構:
我們可以看到本次建構失敗,檢視輸出結果如下:
<a href="http://blog.51cto.com/attachment/201312/181704835.jpg" target="_blank"></a>
當把測試用例修改回正确後,執行建構,釋出正确。
<a href="http://blog.51cto.com/attachment/201312/182504533.jpg" target="_blank"></a>
ok,到此介紹結束.
總結一下:
jenkins根據項目根目錄下的build.xml檔案,并根據jenkins中targets的配置,首先自動執行test,當測試通過後,開始執行tar,打包完成後,開始連結遠端webserver把程式包上傳到遠端webserver指定目錄下,然後再根據jenkins下的command 執行解壓操作,然後就可以根據自己的業務通過shell腳本進行自動處理自動釋出的各項操作.
如果在執行test過程中,出現發現測試用例不通過,則就發出錯誤報告,終止本次建構。
本文轉自birdinroom 51CTO部落格,原文連結:http://blog.51cto.com/birdinroom/1346812,如需轉載請自行聯系原作者