持續(xù)集成---減少持續(xù)集成的時(shí)間
在持續(xù)集成領(lǐng)域,一個(gè)產(chǎn)品的發(fā)布往往都有自己的過(guò)程周期(lifecycle),大體都會(huì)劃分為:構(gòu)建->部署->測(cè)試->發(fā)布等幾個(gè)重要階段,其中測(cè)試是發(fā)布產(chǎn)品前不可或缺的重要階段,是產(chǎn)品質(zhì)量的保證。而能讓持續(xù)集成奏效,除了要求測(cè)試腳本更充分健壯,還要求測(cè)試腳本運(yùn)行得更快更好。這點(diǎn)對(duì)于小型項(xiàng)目而言可能顯得無(wú)關(guān)緊要,畢竟大多小項(xiàng)目的測(cè)試腳本不過(guò)百條,驗(yàn)證點(diǎn)不過(guò)千“點(diǎn)”;但對(duì)于一個(gè)大型項(xiàng)目而言,測(cè)試代碼源文件可能成百上千,執(zhí)行完所有的測(cè)試可能要等很久,而苦等之后的結(jié)果卻可能是滿眼的failure, 于是如果提高測(cè)試執(zhí)行速度成為迫切需要解決的問(wèn)題,試想把測(cè)試階段從2小時(shí)壓縮到1小時(shí),再?gòu)?小時(shí)壓縮到30分鐘,每次時(shí)間壓縮帶來(lái)的不僅是技術(shù)人員本身的成就感,更是對(duì)整個(gè)產(chǎn)品發(fā)布過(guò)程體驗(yàn)的改善。
那么如何加速測(cè)試的執(zhí)行呢?提起速度,我們立馬可能聯(lián)想到“性能”調(diào)優(yōu)的步驟:先進(jìn)行tuning,然后找到問(wèn)題的瓶頸所在,最后逐個(gè)擊破。本文暫不討論如何進(jìn)行這些步驟, 而是基于C++和Java為語(yǔ)言案例,TestNG和Google test為測(cè)試框架,Jenkins為持續(xù)平臺(tái)做分析,從以下六個(gè)層次提出提高測(cè)試執(zhí)行的一般方法:
硬件資源層次
工欲善其事必先利其器,提高硬件(CPU、內(nèi)存、磁盤(pán)等)配置是改善執(zhí)行速度的“硬”方法,硬件資源的優(yōu)化不應(yīng)僅僅局限在單機(jī)自身的各項(xiàng)指標(biāo)提升,在需求不斷提高的情況下,可以考慮實(shí)施虛擬機(jī)、分布式集群等方式來(lái)進(jìn)一步獲取更優(yōu)的硬件資源,當(dāng)然,涉及分布式執(zhí)行時(shí),可以借助以下持續(xù)集成平臺(tái)層次的“軟”實(shí)施來(lái)共同作用。
另外,在硬件資源緊張的情況下,不同項(xiàng)目或者不同團(tuán)隊(duì)可能不得不復(fù)用一套測(cè)試環(huán)境,造成可利用資源更為緊張,此時(shí)可以錯(cuò)開(kāi)時(shí)間測(cè)試(例如A項(xiàng)目組測(cè)試定時(shí)在凌晨0點(diǎn)啟動(dòng),B項(xiàng)目組定時(shí)在凌晨2點(diǎn))以提高速度。
語(yǔ)言編碼實(shí)現(xiàn)層次
測(cè)試代碼本身也是代碼,顯而易見(jiàn),如果代碼編寫(xiě)時(shí)注重效率,速度上肯定有所收益。這點(diǎn)可能需要“糾結(jié)”于一些日常的編碼細(xì)節(jié):例如Java中Stringbuffer和Stringbuilder的比較;C++中是i++和++i的比較。這種語(yǔ)言層次提高效率的文章書(shū)籍很多,這里不做過(guò)多描述。在語(yǔ)言編碼層次上最重要的不是這些語(yǔ)言細(xì)節(jié),而是避免一些消費(fèi)時(shí)間的測(cè)試代碼設(shè)計(jì),減少不必要的耗時(shí)操作,例如以下幾點(diǎn):
(1) 冗余的日志信息,不合理的日志級(jí)別設(shè)置等
輸出日志帶來(lái)的磁盤(pán)頻繁訪問(wèn)必然讓速度下降,所以在保證日志信息充足的前提下,盡量減少日志,或者只記錄失敗測(cè)試的日志(畢竟對(duì)于測(cè)試者而言很少去關(guān)注成功日志),可以讓測(cè)試加快。
(2) 不合理的等待
用戶執(zhí)行完某個(gè)操作,必須等待某條件的發(fā)生(例如DB里面插入一條新數(shù)據(jù))進(jìn)而執(zhí)行后續(xù)動(dòng)作是測(cè)試中經(jīng)常面對(duì)的場(chǎng)景,那么等待多久成為需要考慮的問(wèn)題,假設(shè)用TimeUnit.MINUTES.sleep(1)等待一分鐘,在10秒即可滿足條件的場(chǎng)景下浪費(fèi)的就是50秒,所以這里必須去考慮合理sleep的時(shí)間來(lái)兼顧對(duì)資源的消耗和運(yùn)行速度的影響,同時(shí)在等待方式上也可以考慮是采用循環(huán)短時(shí)間條件等待或異步通知的方式去進(jìn)行。
(3) 用例的過(guò)程
先執(zhí)行完所有測(cè)試步驟,然后做對(duì)所有步驟做一次性校驗(yàn),還是做完一步校驗(yàn)一步,這兩種方式的速度在不同場(chǎng)景下有所不同,所以需要權(quán)衡;相類似的,對(duì)于需要獲取DB連接的用例,是每條都執(zhí)行獲取DB連接然后釋放連接,還是所有用例執(zhí)行之前獲取連接,所有case執(zhí)行完之后釋放連接也會(huì)對(duì)執(zhí)行速度有所影響。
構(gòu)建測(cè)試腳本層次
對(duì)于一個(gè)大型項(xiàng)目,源文件的數(shù)目龐大或依賴的dependency過(guò)多導(dǎo)致代碼編譯占用大量時(shí)間,如何提高編譯代碼的速度?除了使用更好的磁盤(pán),注重代碼編寫(xiě)時(shí)對(duì)編譯速度的影響,還可以針對(duì)不同的語(yǔ)言采取不同的有效策略,例如針對(duì)C++, 使用make命令編譯項(xiàng)目時(shí),可以加上參數(shù)-j來(lái)并行編譯項(xiàng)目。-j參數(shù)的含義可以參考下文:
-j [jobs], --jobs[=jobs]
指定同步運(yùn)行的作業(yè)(命令)的數(shù)量。如果有一個(gè)以上-j選項(xiàng),那么只有最后一個(gè)有效。如果-j選項(xiàng)沒(méi)有參數(shù),那么編譯過(guò)程就不會(huì)限制能夠同步運(yùn)行的作業(yè)的數(shù)量。
需要說(shuō)明的是,編譯過(guò)程可能要求特定的順序而導(dǎo)致并行編譯失敗,如果遇到這種問(wèn)題,可以先并行、后串行(去掉-j)重復(fù)執(zhí)行一次以解決。
而對(duì)于java,Maven 3 開(kāi)始支持并發(fā)build,提供了以下幾種常見(jiàn)方式:
mvn -T 4 clean install # Builds with 4 threads
mvn -T 1C clean install # 1 thread per cpu core
mvn -T 1.5C clean install # 1.5 thread per cpu core
同時(shí)使用maven管理java項(xiàng)目常出現(xiàn)時(shí)間消耗在依賴jar的下載上,此時(shí)可以檢查是否有冗余失效的repository配置、較長(zhǎng)的下載timeout時(shí)間設(shè)置、所選擇repository的連接速度等,甚至在不同測(cè)試環(huán)境下可以使用 profile來(lái)管理repository來(lái)加速測(cè)試腳本構(gòu)建。
測(cè)試框架支持層次
在測(cè)試框架支持層次上,應(yīng)該充分運(yùn)用框架本身提高的豐富功能來(lái)提高測(cè)試執(zhí)行速度,以Java測(cè)試框架TestNG為例:
(1) 利用timeout控制失效等待
如果某個(gè)測(cè)試用例等待某條件的觸發(fā)而陷入長(zhǎng)時(shí)間等待,等待的時(shí)間過(guò)長(zhǎng)往往對(duì)于用例本身而言已失效,特別是當(dāng)條件永遠(yuǎn)無(wú)法滿足時(shí)。因此需要控制用例執(zhí)行允許的最大timeout時(shí)間。TestNG可以給test或者test suite設(shè)置 timeout時(shí)間,分別控制具體某個(gè)或一組(testing.xml配置)自動(dòng)化測(cè)試用例執(zhí)行的最大允許時(shí)間:
1. @Test(timeout = 1000)
2. testng.xml : <suite name="Module Test" parallel="none" time-out="200000">
(2) 利用@BeforeTest、@BeforeClass等條件注解,減少無(wú)意義測(cè)試
測(cè)試的順利完成都需要滿足很多基礎(chǔ)條件,例如需要測(cè)試環(huán)境就緒, 如果不使用@before類標(biāo)簽,則當(dāng)條件不具備時(shí),仍然會(huì)執(zhí)行完所有的用例,必然帶來(lái)巨大的時(shí)間浪費(fèi),因此使用@before類標(biāo)簽可以避免無(wú)意義的測(cè)試,@before標(biāo)記的方法一旦失敗,后續(xù)的相應(yīng)的測(cè)試不會(huì)繼續(xù)進(jìn)行。
(3) 使用框架自帶的多線程支持
例如對(duì)于TestNG自身,可以在testng.xml中設(shè)置parallel參數(shù)來(lái)指定是否并發(fā)以及并發(fā)的級(jí)別:methods|tests|classes,除了測(cè)試框架自身外,軟件項(xiàng)目管理工具也可以提供多線程支持,例如maven的測(cè)試組件maven-surefire-plugin,提供了并發(fā)參數(shù)的設(shè)置:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.16</version> <configuration> <parallel>methods</parallel> <threadCount>10</threadCount> </configuration> </plugin> |
持續(xù)集成平臺(tái)層次
現(xiàn)在市場(chǎng)上存在不少持續(xù)集成平臺(tái),大多持續(xù)集成平臺(tái)支持并發(fā)執(zhí)行用例然后匯總、發(fā)布測(cè)試結(jié)果,從而最大化提高測(cè)試執(zhí)行速度。而并發(fā)執(zhí)行的前提是測(cè)試代碼本身及測(cè)試代碼的組織支持并發(fā),如果測(cè)試本來(lái)就含有多個(gè)模塊,那么直接并發(fā)運(yùn)行多個(gè)模塊,最后匯總結(jié)果即可。如java以testng.xml為模塊,gtest以makefile為模塊,所以相比較順序執(zhí)行4個(gè)模塊,并發(fā)使用4個(gè)Job并發(fā)執(zhí)行,那么時(shí)間壓縮可以達(dá)到4倍。在實(shí)際應(yīng)用中,即使在同一個(gè)模塊,我們?nèi)匀幻鎸?duì)自動(dòng)化測(cè)試用例數(shù)目過(guò)多運(yùn)行速度過(guò)慢的問(wèn)題,此時(shí),可以考慮將單一模塊拆分成子模塊,對(duì)于Java而言較簡(jiǎn)單,配置下測(cè)試套件的xml即可;而對(duì)C++而言,如果不允許直接復(fù)制粘貼原有的makefile,就需要重新設(shè)計(jì)makefile以復(fù)用, 例如將makefile中編譯的test cases定義分拆到多個(gè)makefile(如下圖測(cè)試模塊1的makefile引用了共用的makefile并添加了自己的測(cè)試用例)中,然后并發(fā)執(zhí)行多個(gè)makefile。
為并發(fā)執(zhí)行多個(gè)job, 持續(xù)集成平臺(tái)必須提供必備的支持,以Jenkins為例,可以使用multijob插件來(lái)實(shí)施,配置多個(gè)測(cè)試模塊同時(shí)進(jìn)行.
并發(fā)完測(cè)試后,講所有測(cè)試結(jié)果匯總到一個(gè)地方,然后使用xunit plugin來(lái)匯總結(jié)果(如下圖),它可以匯總多個(gè)文件,且支持cpptest、,gtest等輸出結(jié)果格式。
過(guò)程改進(jìn)層次
在產(chǎn)品的持續(xù)集成生命周期中,可以將測(cè)試拆分成兩部分放在兩個(gè)階段:基本功能快速校驗(yàn)階段(fast fail)和基本功能之外的全面測(cè)試階段。如果產(chǎn)品在第一階段最基本的功能都無(wú)法通過(guò),那么部署之后進(jìn)行全面測(cè)試純屬浪費(fèi)時(shí)間,這個(gè)階段的引入可以快速的校驗(yàn)產(chǎn)品是否有必要開(kāi)展全面測(cè)試。這點(diǎn)類似與測(cè)試用例中添加了@before類標(biāo)簽所帶來(lái)的收效,不過(guò)更宏觀且階段劃分的更清晰。
原有過(guò)程:構(gòu)建階段->部署階段->測(cè)試階段->發(fā)布階段
細(xì)化后過(guò)程:構(gòu)建階段->部署階段->基本功能快速校驗(yàn)階段->全面測(cè)試階段—>發(fā)布階段
這種過(guò)程優(yōu)化可以利用持續(xù)集成平臺(tái)來(lái)支持,例如對(duì)于Jenkins系統(tǒng),可以使用multijob插件,將基本功能快速校驗(yàn)和全面測(cè)試階段分列在不同的phase即可,執(zhí)行效果如下:
結(jié)論
通過(guò)上面由微觀到宏觀六個(gè)不同層次的分析可知,要加速測(cè)試用例的執(zhí)行是一個(gè)系統(tǒng)的過(guò)程,單靠某一方面分析可能有所偏失,并不能將測(cè)試用例的執(zhí)行速度發(fā)揮極致。同時(shí),本文針對(duì)不同層次的分析也沒(méi)有提供step by step的方式描述每一個(gè)細(xì)節(jié),只是點(diǎn)到為止,所以讀者可以根據(jù)自己采用的語(yǔ)言、測(cè)試框架、持續(xù)集成平臺(tái)做類似更有針對(duì)性的分析,相信在綜合不同層次的綜合調(diào)優(yōu)后,可以讓持續(xù)集成實(shí)施的更快、更好。
posted on 2014-06-25 11:39 順其自然EVO 閱讀(244) 評(píng)論(0) 編輯 收藏 所屬分類: 測(cè)試學(xué)習(xí)專欄 、selenium and watir webdrivers 自動(dòng)化測(cè)試學(xué)習(xí)