优美的测试代码 - 行为驱动开发(BDD)
1. SetUp
2. Exercise
3. Verifiy
4. TearDown
一 個(gè)測試案例如果能清晰的區(qū)分這三個(gè)部分,其實(shí)已經(jīng)成功了一半。但是,如果僅僅只是做到這一步,離我們的“可理解的”測試代碼還有些距離。在我看來,要做到 測試代碼的可理解,首先要做到的是使用簡潔清晰的方式表達(dá)每個(gè)測試案例的測試過程。我們都不希望在一個(gè)測試案例中看到一個(gè)long long method,因?yàn)槲覀冃枰ダ斫?#xff0c;你調(diào)用了那么多方法,做了那么多處理,到底是在干啥?當(dāng)然,我們也不希望看到一個(gè)極端情況:一個(gè)測試案例中就看到一個(gè) 函數(shù)調(diào)用。這樣做確實(shí)做到了測試案例表面上的簡潔,但是,卻失去了表現(xiàn)內(nèi)部細(xì)節(jié)的機(jī)會。我們需要表述的是測試過程和方法,比如,進(jìn)行了什么樣的操作,輸入 了什么樣的數(shù)據(jù),然后得出了什么樣的結(jié)果,和預(yù)期結(jié)果對比怎么樣等。如果把這些都封裝到一個(gè)方法,別人只能理解你可能會做什么,但很難去理解你將如何去 做。其次,在測試案例fail的時(shí)候,能夠清晰準(zhǔn)確的定位問題。極限情況下,一個(gè)測試案例里應(yīng)該只能有一個(gè)斷言,或者說一個(gè)檢查點(diǎn)。測試粒度的縮小能夠加 快問題的定位。通常,當(dāng)一個(gè)測試案例fail的時(shí)候,我們還需要定位到底是測試代碼的問題還是被測代碼的問題。這是一個(gè)煩人的過程,定位問題的人不一定就 是寫這段測試代碼的人,就算是寫這段測試代碼的人,也需要時(shí)間去理解測試案例干了什么。這時(shí),測試過程及方法的清晰表述就變得尤為重要。
有的人會 想到通過文檔來表述測試過程和方法,在我看來,這不是一個(gè)好辦法。敏捷開發(fā)中的一個(gè)思想:“一個(gè)過時(shí)的文檔比沒有文檔更加糟糕”。為什么需要文檔才能表述清楚你的測試過程? 只能說明你的測試代碼足夠糟糕,無法讓人理解。一個(gè)糟糕的代碼就算當(dāng)初寫下了足夠詳細(xì)的說明文檔,隨著時(shí)間的交替,人員的變更,代碼的修改維護(hù),復(fù)雜的文 檔和代碼會變得越來越不同步。導(dǎo)致的結(jié)果將會是代碼越來越糟糕復(fù)雜,文檔越來越過時(shí)。最好的文檔,其實(shí)是代碼。
我們先來看一下一個(gè)老外寫的完整的測試案例代碼:
@Test
public?void?shouldBeAbleToEditAPage()?{
????Given.thatThe(wiki).wasAbleTo(beAtThe(PointWhereItHasBeen.JUST_INSTALLED));
????And.thatThe(user).wasAbleTo(navigateToTheHomePage());
????When.the(user).attemptsTo(changeTheContent().to("Welcome?to?Acceptance?Test?Driven?Development"));
????Then.the(textOnTheScreen().ofThe(user)).shouldBe("Welcome?to?Acceptance?Test?Driven?Development");
}
我 之前并沒有為這個(gè)測試案例做任何說明,相信每個(gè)看過這個(gè)測試案例的人都能非常容易的理解這個(gè)測試案例的行為,甚至是對代碼不通的人。因?yàn)樯厦娴臏y試代碼使 用了幾乎是自然語言的方式,描述了其測試的過程。了解的人一定看出來了,其實(shí),這就是行為驅(qū)動開發(fā),Behavior Driven Development,簡稱:BDD。
行為驅(qū)動開發(fā)(Behavior Driven Development)
Behaviour-Driven Development (BDD) is an evolution in the thinking behind TestDrivenDevelopment and AcceptanceTestDrivenPlanning.
It brings together strands from TestDrivenDevelopment and DomainDrivenDesign into an integrated whole, making the relationship between these two powerful approaches to software development more evident.
It aims to help focus development on the delivery of prioritised, verifiable business value by providing a common vocabulary (also referred to as a UbiquitousLanguage) that spans the divide between Business and Technology.BDD 使用幾乎近于自然語言的方式描述了軟件的行為過程,因此,可以直接作為軟件的需求文檔,也可以直接應(yīng)用到測試中,作為測試的標(biāo)準(zhǔn)文檔。我們在做單元測試 時(shí),經(jīng)常是針對某個(gè)函數(shù),或是某個(gè)類進(jìn)行測試,但是被測函數(shù)或是被測的類是可能經(jīng)常變化的,我們的測試案例也需要經(jīng)常性的隨之變化。然后,BDD描述的是軟件的整個(gè)系統(tǒng)行為,幾近于需求文檔,可變性大大減小。因此,測試案例不需要做太大變化。同時(shí),這樣的測試案例最貼近于需求,貼近于實(shí)際的系統(tǒng)行為。
BDD描述的行為就像一個(gè)個(gè)的故事(Story),系統(tǒng)業(yè)務(wù)專家、開發(fā)者、測試人員一起合作,分析軟件的需求,然后將這些需求寫成一個(gè)個(gè)的故事。開發(fā)者負(fù)責(zé)填充這些故事的內(nèi)容,測試者負(fù)責(zé)檢驗(yàn)這些故事的結(jié)果。通常,會使用一個(gè)故事的模板來對故事進(jìn)行描述:
As?a?[X]
I?want?[Y]
so?that?[Z]
同樣的一個(gè)故事,可能會有不同的場景。通過上面的模板描述了故事之后,再通過下面的模板對不同場景進(jìn)行描述:
Given?some?initial?context?(the?givens),
Whenan?eventoccurs,
then?ensure?some?outcomes.
一個(gè)經(jīng)典的例子就是ATM取款機(jī)的例子。故事的描述為:
Title:?Customer?withdraws?cash
As?a?customer,
I?want?to?withdraw?cash?from?an?ATM,
so?that?I?don’t?have?to?wait?inline?at?the?bank.
作為一個(gè)客戶,我去ATM取錢,就不需要去排隊(duì)。同樣的故事,會有不同的場景發(fā)生:
Scenario?1:?Account?is?incredit
Giventhe?account?is?incredit
Andthe?card?isvalid
Andthe?dispenser?contains?cash
Whenthe?customer?requests?cash
Thenensure?the?account?isdebited
Andensure?cash?isdispensed
Andensure?the?card?isreturned
如果你取款的金額比你的存款還多,將是下面的場景:
Scenario?2:?Account?isoverdrawn?past?the?overdraft?limit
Giventhe?account?isoverdrawn
Andthe?card?isvalid
Whenthe?customer?requests?cash
Thenensure?a?rejection?message?isdisplayed
Andensure?cash?isnot?dispensed
Andensure?the?card?isreturned
有了這樣的故事、場景的描述,測試者可以通過一些BDD的測試框架將上面的故事轉(zhuǎn)成測試代碼(當(dāng)然,也可直接由開發(fā)來完成,這里說測試者是為了方便理解),開發(fā)者實(shí)現(xiàn)產(chǎn)品代碼,并保證測試代碼通過。
常見的BDD框架
BOO - Specter: A tool written for the Boo language, a .Net and Mono programming language.
C - CSpec
C++ - CppSpec Spec-CPP
C# .Net - NSpec
.Net - NBehave
.Net - NSpecify (incomplete site)
Delphi - dSpec
Groovy - GSpec, http://easyb.org easyb, tspec a non-English BDD framework with Thai syntax.
Java - JBehave, JDave, beanSpec, Instinct
Javascript - JSSpec
PHP - PHPSpec
Python - Specipy, spec plugin for nose
Ruby - RSpec, Shoulda, test-spec & bacon, Cucumber
Scala - Specs
回到正題
剛才就像對一門新的技術(shù)或方向進(jìn)行了了解,再回過頭來想想,BDD對于測試的意義到底在哪。通過上面的了解,我們知道了行為驅(qū)動開發(fā)并不止是一個(gè)測試行為,其實(shí)很大意義上是一個(gè)產(chǎn)品需求分析人員、開發(fā)、測試共同來完成的一個(gè)行為。BDD同時(shí)也是一個(gè)非常理想化的過程,幾乎現(xiàn)在大部分的公司連TDD都實(shí)現(xiàn)不 了。作為測試人員,我們不是要去抱怨,我們應(yīng)該慶幸作為測試開發(fā)人員,我們有機(jī)會使用最前沿,最先進(jìn)的技術(shù)去解決問題。開發(fā)不能做到TDD,我們可以對自己的測試代碼實(shí)施TDD,我們可以嘗試各種不同的語言,然后選擇最優(yōu)雅的方式去實(shí)現(xiàn)。同樣的,我們可以使用BDD所使用的自然語言描述方法來編寫我們的測試案例。這其實(shí)才是我本文的關(guān)鍵所在。使用行為驅(qū)動開發(fā),還需要打破傳統(tǒng)的魄力。因?yàn)橹皫缀鯖]有人會告訴你一個(gè)函數(shù)的命名為ShouldXXX(),也不會有有When, Then,And之類的類或函數(shù)。當(dāng)你習(xí)慣它,會變得非常好玩。
使用行為驅(qū)動開發(fā),可以使我們的案例描述邏輯更加清晰,可以想象以后維護(hù)你的代碼的人會對你大贊一番,因?yàn)槭∪チ怂斫獯a的大部分時(shí)間。
使用行為驅(qū)動開發(fā),可以建立自動化測試與手工系統(tǒng)測試的橋梁?;蛟S可以形成這樣的模式:手工測試人員負(fù)責(zé)設(shè)計(jì)故事和場景,自動化測試人員負(fù)責(zé)實(shí)現(xiàn)故事和場景。通過這樣的聯(lián)系,手工測試人員能夠更好的了解到自動化測試所做的內(nèi)容,從而免去不必要的重復(fù)勞動。
使用行為驅(qū)動開發(fā),可以使你的測試更加貼近實(shí)際的用戶行為,從而找到系統(tǒng)的問題所在。
沒有銀彈
《沒有銀彈》(No Silver Bullet)是IBM大型電腦之父佛瑞德·布魯克斯(Fred Brooks)在1987年所發(fā)表的一篇關(guān)于軟件工程的 經(jīng)典論文。該論述中強(qiáng)調(diào)由于軟件的復(fù)雜性本質(zhì),而使真正的銀彈并不存在;所謂的沒有銀彈是指沒有任何一項(xiàng)技術(shù)或方法可使軟件工程的生產(chǎn)力在十年內(nèi)提高十 倍。剛才提到的使用行為驅(qū)動開發(fā)的種種好處,但是,如果運(yùn)用不當(dāng),往往會適得其反。我們使用When,Then之類的連詞作為函數(shù),并不是說可以隨意根據(jù) 需要隨意的命名。比如,使用This或These作為函數(shù)名,其行為就應(yīng)該是返回一個(gè)或多個(gè)對象,而不是做其他的事情??梢韵胂?#xff0c;如果一個(gè)函數(shù)的名稱是 These,里面執(zhí)行的確實(shí)一個(gè)文件拷貝的操作,對于代碼的維護(hù)者來說是多么糟糕的一件事情啊。其實(shí)我對行為驅(qū)動開發(fā)也只是初略的了解,本文表達(dá)的是僅僅是我個(gè)人的一些思想,如有錯(cuò)誤之處也希望大家能夠指出。最后,我希望達(dá)到的是:
優(yōu)美的測試代碼,就是一個(gè)個(gè)優(yōu)美的故事。
本文參考資料:
http://behaviour-driven.org/
http://dannorth.net/introducing-bdd
http://www.javaworld.com/javaworld/jw-09-2008/jw-09-easyb.html
轉(zhuǎn)載于:https://www.cnblogs.com/coderzh/archive/2009/07/26/1531633.html
總結(jié)
以上是生活随笔為你收集整理的优美的测试代码 - 行为驱动开发(BDD)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 面向对象编程设计模式--简单工厂模式讲解
- 下一篇: Exchange2003管理