Cucumber是Ruby世界的BDD框架,開發(fā)人員主要與兩類文件打交到,F(xiàn)eature文件和相應(yīng)的Step文件。Feature文件是以feature為后綴名的文件,以Given-When-Then的方式描述了系統(tǒng)的場景(scenarios)行為;Step文件為普通的Ruby文件,F(xiàn)eature文件中的每個Given/When/Then步驟在Step文件中都有對應(yīng)的Ruby執(zhí)行代碼,兩類文件通過正則表達式相關(guān)聯(lián)。筆者在用Cucumber+Watir做回歸測試時對Cucumber工程的目錄結(jié)構(gòu)執(zhí)行過程進行了研究。
安裝好Cucumber后,如果在終端直接執(zhí)行cucumber命令,得到以下輸出:
輸出結(jié)果表明:cucumber期待當(dāng)前目錄下存在名為features的子目錄。建好features文件夾后,重新執(zhí)行cucumber命令,輸出如下:

Cucumber運行成功,但由于features文件夾下沒有任何內(nèi)容,故得到上述輸出結(jié)果。
網(wǎng)上大多數(shù)關(guān)于Cucumber的教程都建議采用以下目錄結(jié)構(gòu),所有的文件(夾)都位于features文件夾下。

Feature文件(如test.feature)直接位于features文件夾下,可以為每個應(yīng)用場景創(chuàng)建一個Feature文件;與Feature文件對應(yīng)的Step文件(如test.rb)位于step_definitions子文件夾下;同時,存在support子文件夾,其下的env.rb文件為環(huán)境配置文件。在這樣的目錄結(jié)構(gòu)條件下執(zhí)行cucumber命令,會首先執(zhí)行env.rb做前期準備工作,比如可以用Watir新建瀏覽器窗口,然后Cucumber將test.rb文件讀入內(nèi)存,最后執(zhí)行test.feature文件,當(dāng)遇到Given/When/Then步驟時,Cucumber將在test.rb中搜索是否有相應(yīng)的step,如果有,則執(zhí)行相應(yīng)的Ruby代碼。
這樣的目錄結(jié)構(gòu)只是推薦的目錄結(jié)構(gòu),筆者通過反復(fù)的試驗得出了以下結(jié)論:對于Cucumber而言,除了頂層的features文件夾是強制性的之外,其它目錄結(jié)構(gòu)都不是強制性的,Cucumber將對features文件夾下的所有內(nèi)容進行扁平化(flatten)處理和首字母排序。具體來說,Cucumber在運行時,首先將遞歸的執(zhí)行features文件夾下的所有Ruby文件(其中則包括Step文件),然后通過相同的方式執(zhí)行Feature文件。但是,如果features文件夾下存在support子文件夾,并且support下有名為env.rb的文件,Cucumber將首先執(zhí)行該文件,然后執(zhí)行support下的其它文件,再遞歸執(zhí)行featues下的其它文件。
比如有如下Cucumber目錄結(jié)構(gòu):

為了方便記錄Cucumber運行時的文件執(zhí)行順序,在features文件夾下的所有Ruby文件中加上以下代碼:
puts File.basename(__FILE__)
此行代碼的作用是在一個Ruby文件執(zhí)行時輸出該文件的名字,此時執(zhí)行cucumber命令,得到以下輸出(部分)結(jié)果:

上圖即為Ruby文件的執(zhí)行順序,可以看出,support文件夾下env.rb文件首先被執(zhí)行,其次按照字母排序執(zhí)行c.rb和d.rb;接下來,Cucumber將features文件夾下的所用文件(夾)扁平化,并按字母順序排序,從而先執(zhí)行a.rb和b.rb,而由于other文件夾排在step_definitions文件夾的前面,所以先執(zhí)行other文件夾下的Ruby文件(也是按字母順序執(zhí)行:先f.rb,然后g.rb),最后執(zhí)行step_definitions下的e.rb。
當(dāng)執(zhí)行完所有Ruby文件后,Cucumber開始依次讀取Feature文件,執(zhí)行順序也和前述一樣,即: a.feature --> b.feature --> c.feature
筆者還發(fā)現(xiàn),這些Ruby文件甚至可以位于features文件夾之外的任何地方,只是需要在位于features文件夾之內(nèi)的Ruby文件中require一下,比如在env.rb中。