隨著敏捷越來越廣為人知,敏捷測(cè)試也更多受到了大家的關(guān)注。在這里,我想談一下我在敏捷項(xiàng)目中遇到的一個(gè)自動(dòng)化測(cè)試相關(guān)問題以及我們?nèi)绾谓柚鶧SL領(lǐng)域?qū)S谜Z言來解決它。 對(duì)敏捷軟件開發(fā)方法有一定了解的人都知道,敏捷軟件開發(fā)過程是一個(gè)迭代式交付的過程。每個(gè)迭代相當(dāng)于比較小型的交付周期。那么,為了配合頻繁的軟件交付,敏捷測(cè)試相對(duì)于傳統(tǒng)測(cè)試必須要做相應(yīng)的調(diào)整。這也導(dǎo)致了敏捷項(xiàng)目中的測(cè)試面臨幾個(gè)特有的挑戰(zhàn):
自動(dòng)化測(cè)試在應(yīng)對(duì)頻繁的回歸測(cè)試這個(gè)挑戰(zhàn)上起著非常關(guān)鍵的作用。自動(dòng)化測(cè)試做不好,團(tuán)隊(duì)最終會(huì)被每個(gè)迭代都會(huì)增加的回歸測(cè)試工作量壓垮。我經(jīng)歷過的一個(gè)團(tuán)隊(duì),在這個(gè)團(tuán)隊(duì)中,大家很早就意識(shí)到了自動(dòng)化測(cè)試的重要性,在自動(dòng)化測(cè)試上的投入不遺余力。我們相信自動(dòng)化功能測(cè)試增加到足夠多的時(shí)候,它就能指導(dǎo)手動(dòng)回歸測(cè)試,保證整個(gè)交付過程順利進(jìn)行。 的確,自動(dòng)化測(cè)試剛開始進(jìn)行的時(shí)候,我們收益頗多。每增加一個(gè)自動(dòng)化測(cè)試,我們就能減少一些手動(dòng)測(cè)試。自動(dòng)化測(cè)試讓我們我們有比較充裕的時(shí)間來手動(dòng)測(cè)試那些還沒有來得及自動(dòng)化的、難以被自動(dòng)化的功能點(diǎn)上,而且還能有時(shí)間和精力做探索性測(cè)試。這個(gè)結(jié)果讓團(tuán)隊(duì)感到生活很美好,也讓我們對(duì)自動(dòng)化測(cè)試堅(jiān)信不疑。 然而好景不長(zhǎng),隨著自動(dòng)化測(cè)試的不斷增加,我們會(huì)面臨這樣一些問題:
于是,我們的手動(dòng)測(cè)試越來越難得到自動(dòng)化測(cè)試的幫助。它開始成了項(xiàng)目的雞肋。測(cè)試代碼閱讀困難、維護(hù)困難以及測(cè)試結(jié)果的看起來也很費(fèi)勁。這直接導(dǎo)致了我們不僅要投入相當(dāng)?shù)臅r(shí)間來增加自動(dòng)化測(cè)試,也要投入不少時(shí)間來閱讀并利用測(cè)試結(jié)果。 于是我們開始重新審視自動(dòng)化測(cè)試的做法,繼續(xù)摸索更好的方式。 很快,我們發(fā)現(xiàn)“能夠跑起來”并不是好的自動(dòng)化測(cè)試僅需的特性。讓我們通過一段測(cè)試代碼來看一下具體怎么回事。 selenium.open(“/”)selenium.type(“id=username”, “myname”)selenium.type(“id=password”, “mypassword”)selenium.click(“id=btnLogin”)selenium.waitForPageToLoad(30000)assertTrue(selenium.isTextPresent(“Welcome to our website!”)) 這個(gè)測(cè)試中,我們首先打開了一個(gè)頁(yè)面,在頁(yè)面中尋找一個(gè)id為username的輸入框,輸入“myname”,然后再尋找一個(gè)id為password的輸入框,輸入“password”,然后點(diǎn)擊一個(gè)id為btnLogin的按鈕,等待30秒以后,斷言頁(yè)面應(yīng)該出現(xiàn)的文字。 我們可以看到,這個(gè)測(cè)試的實(shí)現(xiàn)很完整的描述了測(cè)試的操作過程,是一個(gè)面向步驟而不是目的的描述。當(dāng)然,稍加分析,我們也可以看出來這個(gè)測(cè)試的目的是測(cè)用戶登錄成功系統(tǒng)。 但是,想象當(dāng)我們有很多這樣面向步驟來描述的測(cè)試時(shí),要從中抽離出被無數(shù)細(xì)碎的操作步驟所淹沒的測(cè)試意圖,并把測(cè)試的結(jié)果利用起來,其實(shí)并沒有那么直觀。而且,如果在測(cè)試中出現(xiàn)了錯(cuò)誤,對(duì)于問題的具體功能點(diǎn)的定位也不是那么容易。 與此同時(shí),并不是團(tuán)隊(duì)中所有的成員都有能力閱讀和編寫這樣的測(cè)試。這無疑降低了團(tuán)隊(duì)成員對(duì)于自動(dòng)化測(cè)試的參與度。對(duì)于客戶,自動(dòng)化測(cè)試更是一個(gè)黑盒子,做了什么,沒做什么,基本上搞不清,更談不上參與到自動(dòng)化測(cè)試中,幫助提高測(cè)試的有效性。 種種狀況,究其原因就是測(cè)試可讀性太差,測(cè)試意圖不夠明顯??蛇\(yùn)行并且容易讀的測(cè)試才是好的自動(dòng)化測(cè)試。這樣才能夠保證任何時(shí)候,我們不會(huì)喪失對(duì)于測(cè)試案例的跟蹤與管理。測(cè)試人員隨時(shí)都可以通過快速閱讀測(cè)試,了解那些功能已經(jīng)被自動(dòng)化測(cè)試覆蓋,有效規(guī)劃手工測(cè)試的工作量。 怎么提高測(cè)試的可讀性呢? 我們的解決辦法是DSL領(lǐng)域?qū)S谜Z言。 什么是領(lǐng)域?qū)S谜Z言?在馬丁大叔的博客里有比較詳細(xì)的描述。大致來說,領(lǐng)域?qū)S谜Z言就是針對(duì)某個(gè)領(lǐng)域的特定目的編程語言。不像Java、C#等通用語言,可以解決任何領(lǐng)域的問題。領(lǐng)域?qū)S谜Z言通過自己獨(dú)特的語法結(jié)構(gòu)來描述更接近于專業(yè)領(lǐng)域語言的業(yè)務(wù)。 讓測(cè)試的描述能夠接近被測(cè)系統(tǒng)的領(lǐng)域語言、使測(cè)試意圖得到清晰表達(dá)就是我們想要得到的效果。DSL正好能夠幫我們實(shí)現(xiàn)。 讓我們?cè)倏纯粗暗哪嵌未a: selenium.open(“/”)selenium.type(“id=username”, “myname”)selenium.type(“id=password”, “mypassword”)selenium.click(“id=btnLogin”)selenium.waitForPageToLoad(30000)assertTrue(selenium.isTextPresent(“Welcome to our website!”)) 由于使用的是通用語言,在我們這個(gè)特定的使用場(chǎng)景中顯得過于細(xì)節(jié)化、過程化,不能清晰表達(dá)測(cè)試意圖。 換成DSL,我們的測(cè)試就可以直接用驗(yàn)收標(biāo)準(zhǔn)的語言來描述如下: Given I am on login pageWhen I provide username and passwordThen I can enter the system 這樣測(cè)試的內(nèi)容就直觀多了,還包含了一些業(yè)務(wù)信息,讓我們知道這個(gè)是在測(cè)試一個(gè)登錄的場(chǎng)景,而不是任意的輸入信息,兼顧傳遞了業(yè)務(wù)知識(shí)的職責(zé)。至于這些DSL背后能夠運(yùn)行的代碼,也被隱藏起來。如果是不能夠閱讀原來那樣的測(cè)試代碼的人(不管是需求分析人員還是客戶甚至一些對(duì)自動(dòng)化代碼關(guān)注比較少的測(cè)試人員)想要加入到自動(dòng)化測(cè)試活動(dòng)中進(jìn)行反饋,就不會(huì)被DSL背后的代碼帶來的“噪音”所影響。 當(dāng)然,在我們的現(xiàn)實(shí)應(yīng)用場(chǎng)景中,這個(gè)需求沒有那么簡(jiǎn)單,我們的驗(yàn)收標(biāo)準(zhǔn)還會(huì)考慮不同的數(shù)據(jù)比如輸入不同組合的用戶名密碼: Given I am on login pageWhen I provide ‘david’ and ‘davidpassword’Then I can enter the systemGiven I am on login pageWhen I provide ‘kate’ and ‘kate_p@ssword’Then I can enter the system 以及更多的測(cè)試數(shù)據(jù)。 那么這種情況下,僅僅是比較通俗的語言還是不夠的,畢竟測(cè)試數(shù)量在那擺著。如果測(cè)試數(shù)量不能減少,維護(hù)起來仍然很麻煩。打個(gè)比方,如果系統(tǒng)的實(shí)現(xiàn)變成了每次都要輸入用戶名、密碼和一個(gè)隨機(jī)驗(yàn)證碼,我們就需要在我們的自動(dòng)化測(cè)試中修改多處,比較繁瑣。因此,我們需要在可讀性比較好的自然語言描述的測(cè)試上,把它的抽象層次再提高一點(diǎn)。 幸運(yùn)的是,我們當(dāng)時(shí)選擇的DSL工具是cucumber,它除了提供了幾個(gè)測(cè)試的描述層次:Feature,Scenario,Steps,還提供了非常好的一種組織方式—數(shù)據(jù)表。 這樣,我們的這個(gè)自動(dòng)化測(cè)試就可以把之前的那個(gè)登錄的功能根據(jù)特性、場(chǎng)景總結(jié)和具體的步驟分離開來,清晰的分層,同時(shí)利用數(shù)據(jù)表我們的測(cè)試精簡(jiǎn)成一系列被重復(fù)多次但輸入數(shù)據(jù)有所變化的操作過程,如下: Feature: authenticationIn order to have personalized informationI want to access my account by providing authentication informationSo that the system can know who I amScenario Outline: login successfullyGiven I am on login pageWhen I provide ‘ 測(cè)試這下看起來就更清爽了。首先,用Feature關(guān)鍵字,我們把測(cè)試分類到login這個(gè)大特性下的,并對(duì)這個(gè)特性本身的業(yè)務(wù)目的進(jìn)行相關(guān)描述,帶進(jìn)業(yè)務(wù)目標(biāo),傳遞業(yè)務(wù)知識(shí);然后用Scenario關(guān)鍵字來提高挈領(lǐng)的標(biāo)明我們這個(gè)測(cè)試場(chǎng)景中做的是測(cè)試登錄成功的情況,并且把步驟都寫出來;最后,我們用Examples關(guān)鍵字引出具體的數(shù)據(jù)表格把用到的數(shù)據(jù)都展示出來,避免我們的相同步驟因?yàn)闇y(cè)試數(shù)據(jù)的變化而重復(fù)若干遍造成冗余。萬一碰上了需求的變化,要求同時(shí)提供用戶名、密碼和驗(yàn)證碼,那我們的測(cè)試也只需要改動(dòng)較少的地方就足夠了。 更棒的是,用了這種數(shù)據(jù)表的方式,整個(gè)團(tuán)隊(duì)的協(xié)作效率提高了。對(duì)于寫代碼沒有那么順暢的測(cè)試人員來說,增加自動(dòng)化測(cè)試也就是增加更多測(cè)試數(shù)據(jù),填充到數(shù)據(jù)表里就可以了。 就這樣,我們用DSL實(shí)現(xiàn)了可執(zhí)行的可讀性高的文檔。幫助了回歸測(cè)試,降低了文檔維護(hù)難度,也促進(jìn)團(tuán)隊(duì)成員利用測(cè)試來傳遞知識(shí)的積極性,讓更多人能夠參與到測(cè)試中。如果您的團(tuán)隊(duì)也遇到了類似的問題,不妨也嘗試一下。 本文原文發(fā)表于InfoQ:http://www./cn/articles/leveraging-dsl-in-agile-test |
|