文檔即測(cè)試?
首先看一下以下這段文字: 引用 Feature: Sign in In order to get access to protected sections of the site A user Should be able to sign in Scenario: User is not signed up Given no user exists with an email of "email@person.com" When I go to the sign in page And I sign in as "email@person.com/password" Then I should see "Bad email or password" And I should not be signed in Scenario: User is not confirmed Given I signed up with "email@person.com/password" When I go to the sign in page And I sign in as "email@person.com/password" Then I should see "Your account is not active" And I should not be signed in Scenario: User enters wrong password Given I am signed up and confirmed as "email@person.com/password" When I go to the sign in page And I sign in as "email@person.com/wrongpassword" Then I should see "Bad email or password" And I should not be signed in Scenario: User signs in successfully Given I am signed up and confirmed as "email@person.com/password" When I go to the sign in page And I sign in as "email@person.com/password" Then I should see "Signed in successfully" And I should be signed in Scenario: User signs in and checks "remember me" Given I am signed up and confirmed as "email@person.com/password" When I go to the sign in page And I sign in with "remember me" as "email@person.com/password" Then I should see "Signed in successfully" And I should be signed in When I return next time Then I should be signed in 第一印象就是一段關(guān)于用戶登錄的文檔描述吧? 但實(shí)際上,這是一段實(shí)際項(xiàng)目中關(guān)于用戶登錄場(chǎng)景的集成測(cè)試“代碼” 測(cè)試即文檔? 準(zhǔn)確來說,以上代碼是在一個(gè)ROR項(xiàng)目中使用Cucumber進(jìn)行BDD開發(fā)的一個(gè)場(chǎng)景描述(測(cè)試)。 什么是BDD? http://en./wiki/Behavior_Driven_Development 這不是文本重點(diǎn),有興趣的同學(xué)可以自行搜索更多文章。 為什么要BDD? 說到BDD,就不得不提TDD(http://en./wiki/Test-driven_development) TDD的開發(fā)流程: Javaeye上有篇老帖子: 什么是“測(cè)試驅(qū)動(dòng)開發(fā)” (http://www./topic/20063 ),點(diǎn)出了為什么要進(jìn)行TDD的幾個(gè)關(guān)鍵問題: 第一,自然語言的描述容易產(chǎn)生歧義 第二,不能自動(dòng)化地驗(yàn)證 第三,不能保證文檔與程序同步 TDD強(qiáng)調(diào)的是功能模塊的測(cè)試,很多人都愿意使用單元測(cè)試,想嘗試TDD,但都會(huì)有個(gè)問題,不知從哪里開始下手,而我們面向更多的是對(duì)一個(gè)場(chǎng)景的實(shí)現(xiàn),因此BDD應(yīng)運(yùn)而生,更符合開發(fā)者的思維習(xí)慣。 做開發(fā),不能沒有文檔。我們做開發(fā)時(shí),一般都是先接到一個(gè)需求描述(簡(jiǎn)單文檔),我們作為開發(fā)者,要做的工作就是實(shí)現(xiàn)這個(gè)功能(場(chǎng)景)的代碼編寫,例如用戶注冊(cè)、用戶登錄、忘記密碼的流程。 而Cucumber就是為我們提供了這么一個(gè)工具,讓我們能在用簡(jiǎn)單語言描述我們要做的事情同時(shí),也順帶完成了測(cè)試代碼的編寫,剩下的就類似是做 填空題一樣,逐步編寫實(shí)現(xiàn)代碼,讓所有測(cè)試都通過。當(dāng)所有實(shí)現(xiàn)代碼都出來了,一個(gè)完整的項(xiàng)目也就出來了(文檔+代碼+測(cè)試)。這也符合Rails DRY原則,不要做重復(fù)工作。 引用 “軟件工程課講得清楚,只有源代碼的軟件不能算軟件,因?yàn)樗豢衫斫?、不可維護(hù);源代碼加上文檔,才算是程序員完整地交付了自己的工作?!?/div>
引用自 http://www./topic/20063 我覺得還需要加上測(cè)試,才算是一個(gè)完整的項(xiàng)目。 怎么在Ruby on Rails 中怎么使用Cucumber進(jìn)行BDD開發(fā)? 什么是Cucumber? 項(xiàng)目主頁:http:/// 引用 Cucumber is
Aslak Helles?y’s rewrite of RSpec’s “Story runner”, which was originally
written by Dan North. (Which again was a rewrite of his first
implementation - “RBehave”). Early versions of “Story runner” required
that stories be written in Ruby. Shortly after, David Chelimsky added
plain text support with contributions from half a dozen other people.
為什么選擇Cucumber? 在 Rails 已經(jīng)有一些BDD 工具: Rspec (http:///) 使用的測(cè)試代碼類似:
雖然也很DSL,但還不夠簡(jiǎn)明、直觀,“代碼”的味道還是很重。對(duì)比之下,反觀Cucumber的測(cè)試“代碼”,即使是團(tuán)隊(duì)中不會(huì)編程的角色也能 看得明白在描述什么。如果團(tuán)隊(duì)足夠NB,可以有一個(gè)負(fù)責(zé)程序設(shè)計(jì) 的leader專門負(fù)責(zé)把需求用Cucumber的features來描述,根據(jù)各人的能力和工作量,再分發(fā)給其下的負(fù)責(zé)編碼的開發(fā)人員進(jìn)行實(shí)現(xiàn)的編碼。 Cucumber的開發(fā)過程 ![]() (from http://www./titles/achbd/the-rspec-book) 具體過程,7個(gè)步驟: 引用 1: Describe behaviour in plain text 2: Write a step definition in Ruby 3: Run and watch it fail 4: Write code to make the step pass 5: Run again and see the step pass 6: Repeat 2-5 until green like a cuke 7: Repeat 1-6 until the money runs out 簡(jiǎn)單來說就是:寫用例->跑測(cè)試->看結(jié)果->寫實(shí)現(xiàn)->換個(gè)用例,再來一次 具體安裝設(shè)置細(xì)節(jié)略過,Cucumber新手上路可以看視頻: http:///episodes/155-beginning-with-cucumber 或者文字版: http:///episodes/155-beginning-with-cucumber Cucumber能做什么? 看看用Cucumber可以描述、測(cè)試多復(fù)雜的場(chǎng)景: 測(cè)試發(fā)郵件?沒問題: ![]() 甚至可以把一個(gè)用戶進(jìn)行填寫注冊(cè)表單、登錄自己的郵箱、查收激活郵件、點(diǎn)擊激活鏈接的整個(gè)故事流程都跑起來: ![]() 又一個(gè)常見場(chǎng)景: 已注冊(cè)用戶忘記密碼,然后通過點(diǎn)擊“忘記密碼”鏈接,系統(tǒng)發(fā)送激活鏈接到用戶郵箱,用戶通過打開郵箱中的更改密碼鏈接,進(jìn)入新密碼修改頁面,修改新密碼后能成功登錄: ![]() 用cucumber features -n 命令跑測(cè)試的效果: ![]() 一些基本技巧: 在其他場(chǎng)景中,經(jīng)常會(huì)用前面測(cè)試過的“一個(gè)注冊(cè)并激活的用戶”,每次都copy一次? Don't repeat yourself! 此時(shí)就可以在Cucumnber的steps中把上述過程都封裝成一句話:
實(shí)際的封裝steps代碼是: ![]() 第一步是新建一個(gè)已激活的用戶,第二步是用這個(gè)用戶來進(jìn)行登錄操作,這樣就得到了一個(gè)“注冊(cè)并已激活,已經(jīng)成功登錄的用戶” 看看另一個(gè)測(cè)試用例,也是比較“經(jīng)典”的在一個(gè)項(xiàng)目中新建一個(gè)todo item的場(chǎng)景: ![]() 其中
的steps實(shí)現(xiàn)為: ![]() 通過這樣的封裝,可以用來斷定任意兩個(gè)model數(shù)據(jù)對(duì)象是否關(guān)聯(lián) 可通用的描述語句為:
一些進(jìn)階技巧: http:///episodes/159-more-on-cucumber 示范如何做通過設(shè)置模板句法來解決一些重復(fù)、相似的features編寫技巧 如:
但我個(gè)人不推薦過多的使用這種技巧,我認(rèn)為Cucumber的features就應(yīng)該保持簡(jiǎn)明易懂,去除代碼的味道。features里套用了模 板,人閱讀時(shí)就需要用腦“即時(shí)編譯”,進(jìn)行循環(huán)、替換,這就又會(huì)給缺乏編程經(jīng)驗(yàn)的人作為功能描述文檔閱讀時(shí)造成障礙,削弱了“測(cè)試即文檔”的作用。DRY 不是圣旨,適當(dāng)?shù)闹貜?fù)并不是罪惡。 另外,在cucumber中使用webrat進(jìn)行測(cè)試時(shí),還可以搭配使用Selenium 來測(cè)試JS,十分強(qiáng)大,這會(huì)是我們下一步的嘗試。 感受: 當(dāng)我第一次看到Cucumber的測(cè)試代碼,第一個(gè)感覺就是這真的是“代碼”嗎?很奇幻的感覺。 現(xiàn)在感覺Cucumber中的features的本質(zhì)無非是一些用關(guān)鍵詞堆砌的文本段落,然后一個(gè)用正則替換的方法來匹配替換真正的測(cè)試語句, 很簡(jiǎn)單的手段,但最重要的背后的思考,它是bdd所強(qiáng)調(diào)一種開發(fā)風(fēng)格、思維方式。 在用Cucumber開發(fā)了一段時(shí)間后,完全沒有感覺不適或強(qiáng)迫感,每次看到測(cè)試通過后的一片綠色,心情就很輕松愉快。能很明確每一步在做什么, 而且做完修改后,都能知道修改有沒副作用。Ruby之父說用ruby開發(fā)是happy coding,開始以為just joking,現(xiàn)在真的有這種感覺,現(xiàn)在用Cucumber進(jìn)行BDD則是多了一個(gè)項(xiàng):happy testting 疑問? I18n怎么處理? Rails 有了Cucumber后,還需要單元測(cè)試嗎? http://www./blogs/2009/06/cucumber-rocks-but-its-not-a-replacement-for-unit-tests/ 關(guān)于這個(gè)問題,我和同事都認(rèn)為是需要的,只是在一些細(xì)節(jié)上有爭(zhēng)議。 我在實(shí)際進(jìn)行項(xiàng)目開發(fā)時(shí),都是針對(duì)一個(gè)應(yīng)用場(chǎng)景、案例、用戶故事的思路來進(jìn)行代碼編寫的,只有當(dāng)流程跑通了(features 的測(cè)試通過),下一步才是保證這個(gè)流程在一些異常情況下也能得到預(yù)期的結(jié)果(用單元測(cè)試來保證,如更多的邊界測(cè)試),簡(jiǎn)單來說是就 setup features->coding->unit test 同事認(rèn)為,應(yīng)該在寫完cucumber的測(cè)試代碼后,再寫單元測(cè)試代碼,最后再寫實(shí)現(xiàn)代碼,簡(jiǎn)單來說是 setup features ->unit test->coding 我不清楚到底那種才是正確的BDD流程,這需要繼續(xù)探討。 以上是我一個(gè)月來嘗試BDD的經(jīng)驗(yàn)分享,作為拋磚,其中或許有片面或錯(cuò)誤的見解,望有同學(xué)們不吝指教、一起探討。 有研究表明,三個(gè)星期可以改變或養(yǎng)成一個(gè)習(xí)慣,那你今天開始BDD了嗎? 相關(guān)鏈接: What is Test-driven Development? http://edn./article/29690 Behavior Driven Development Using Ruby http://www./pub/a/ruby/2007/08/09/behavior-driven-development-using-ruby-part-1.html http://www./pub/a/ruby/2007/08/30/behavior-driven-development-using-ruby-part-2.html Introduction to BDD with Cucumber http://www./blog/2009/cucumber-introduction/ A NEW LOOK AT TEST-DRIVEN DEVELOPMENT http://blog./files/BDD_Intro.pdf 本文PDF版(帶排版): http://www./topics/download/69f11949-58ed-33dd-8307-884d280ebad5 不錯(cuò),現(xiàn)在一直在用Cucumber 直接支持中文場(chǎng)景描述,而且可以使用場(chǎng)景大綱+例子的方式測(cè)試同一的用例不同條件的情況
BDD在rails社區(qū)倒是非常流行,從某種程度上來說,也是得益于rails很方便得能夠DSL帶來得。
這就是我想要的開發(fā)模式。
曾經(jīng)在團(tuán)隊(duì)中用過這種模式,當(dāng)時(shí)是以u(píng)ser story驅(qū)動(dòng)。一個(gè)user stroy就類似這里的behavior。效果很好,能讓大家能充分明白開發(fā)任務(wù)和入手點(diǎn)。 不知道這些behavior是如何組織和管理的,是否能全部串聯(lián)起來成為一個(gè)真正完整的用例描述文檔。 genki 寫道 個(gè)人認(rèn)為 setup features ->unit test->coding 是比較正確的流程??戳撕芏嘟坛贪╮ailscasts里面都是用這個(gè)流程,實(shí)踐起來也蠻暢快的。
發(fā)現(xiàn)一開始使用BDD的時(shí)候不知道從哪入手,寫了很多蹩腳的測(cè)試用例,搞得生產(chǎn)力很低下。后面看了很多教程后找到感覺就順暢了,重構(gòu)起來心里也比較有底. 我是這樣考量的,因?yàn)閷?shí)際開發(fā)時(shí),其實(shí)很多需求都是模糊不定的,有些細(xì)節(jié)問題只有把流程實(shí)現(xiàn)出來后才能發(fā)現(xiàn),需求可能又會(huì)變動(dòng)了,所以我才延遲了ut的編寫。我是等流程完全確定了,才開始編寫一些關(guān)鍵的UT保證邊界值和一些可預(yù)見的異常測(cè)試
其實(shí)這種 DSL 很像自定語法:
ps:以前還寫了個(gè)從 Story 生成/檢查測(cè)試骨架的腳本 …… BDD 保證團(tuán)隊(duì)產(chǎn)品質(zhì)量和穩(wěn)定進(jìn)展還是挺有效的。 但是額外的單元測(cè)試不建議寫太多太細(xì) …… 除了測(cè)試外,還可以借助一些代碼工具(譬如搞類型推斷的 DRuby ……)進(jìn)行檢查,減少重復(fù)勞動(dòng)。 多嘴一下: BDD和ruby是沒半毛錢關(guān)系的,其他語言也有類似的BDD框架,比如StoryQ是.net的BDD框架 ROR項(xiàng)目中使用Cucumber進(jìn)行BDD開發(fā),Cucumber是用ruby編寫的一個(gè)bdd工具
而Cucumber就是為我們提供了這么一個(gè)工具,讓我們能在用簡(jiǎn)單語言描述我們要做的事情同時(shí),也順帶完成了測(cè)試代碼的編寫
什么是Cucumber? 項(xiàng)目主頁:http:///
你若打開Cucumber的項(xiàng)目主頁,就會(huì)發(fā)現(xiàn)它的標(biāo)題是: Cucumber - Making BDD fun
|
|