天天看點

TDD,Dont DDT

一直有個疑問,對于遺留系統,我們該如何TDD

我個人比較認同TDD是一種設計方法,不能代替真正意義上的測試。是幫助我們設計自己代碼的一種方法。對于遺留系統,面對一堆需求文檔,面對一陀陀已經難

以繼續維護的陳舊代碼,你的心是否哇涼哇涼的

?做為一個使用Rails的開發人員,難道你要把這些代碼翻譯為Ruby代碼嗎

答案當然是不!

很多時候,我們雖然很清楚要TDD,但是很多時候我們是在DDT。基本上是根據遺留系統的代碼把功能代碼寫的差不多了,才想起來寫測試。寫完之後,

用流行的rcov測試一下測試代碼覆寫率,不足的地方再加上測試

? 回頭想想,我們引入TDD的初衷是這樣的嗎

? 大家都心知肚明,并不是這樣的!

重新思考TDD之後,我決定在現做的這個ticket裡完全采用了TDD的方式去開發,今天一天下來,感觸頗深:

1。

昨天拿到php源碼,一看代碼,了不得啊,和我功能相關的源碼檔案之有三個,但代碼卻有三千多行。我該怎麼辦

?我肯定不可能把那三千多行都看完吧。我該如何TDD

     T代表Test,測試驅動開發,很顯然,是先有測試,要不談何驅動開發。

但是沒有功能代碼,你測試什麼呀?

既然TDD是一種設計方法,那麼這個測試,代表的應該是你大腦中對這個功能的自我認知。

如果對需求了解不清楚,你是沒有辦法對這個功能産生自我的認知的。硬着頭皮整理了一下需求文檔,在腦中形成一個大概的輪廓之後,就可以動手寫測試了。此功

能是要生成一個報表,就是一個create -> show

的過程。一般人想到的先是頁面,我是一般人,是以我也是從頁面開始的,根據已經明确的需求寫下自己對這個頁面的幻想:

  /spec/views/reports/new.html.erb_spec.rb中:

  require File.dirname(__FILE__) + '/../../spec_helper'

   describe "reports/new.html.erb" do

       ....  ..

       it "should render new.html.erb" do

         render "/reports/new.html.erb"

         response.should have_tag("form[action=/reports/new]") do

          #應該有一個label來表明這個field是company name

            with_tag('label',"company name:")                                                      

            with_tag('select#data_company_id[name=?]',"data[company_id]")        

        #應該有個下拉清單來讓使用者選擇存在的company name

            with_tag('label',"Report Filter by Year:")                                                    

           #應該有個時間清單來讓使用者選擇生成報表資料的時間段。 with_tag('select#report_filter_by_year[name=?]',"report_filter[by_year]")

          end

        end

       .... ..

     end

好了,寫到這,我腦中隻剩下了一點不清楚的需求。也就是說,我如果能把這個測試寫完,腦中對這部分的需求應該就明朗了。繼續看文檔,看php代碼,隻看一

些sql語句。一個疑問就是這個頁面用不用加一個排序的下拉清單

? 這個疑問得問和我們合作的老外Andy,正好他還未到睡覺時間,就問他:

       new page whether should need 

select down list to  sort by  some  column ?  他回答

: sounds  like good .

  very good ,   我可以把上面這句英語翻譯成rspec代碼:

             with_tag('label',"Sort by:")

       with_tag('select#sort_by_sorted_on[name=?]',"sort_by[sorted_on]")

這樣我的這個測試就全部寫完了:如下

require File.dirname(__FILE__) + '/../../spec_helper'

             with_tag('select#report_filter_by_year[name=?]',"report_filter[by_year]")

            with_tag('label',"Sort by:")

           with_tag('select#sort_by_sorted_on[name=?]',"sort_by[sorted_on]")

打開autotest,運作,報錯:沒有這個頁面。好辦啊,建個頁面不就得了。建立new.html.erb.

    運作測試,報錯,沒有

<label> company name: </label>,

好辦啊,在new.html.erb裡加個label不就得了。

    根據錯誤資訊的提示,我很快就把頁面的基本元素寫好了。

但是下拉清單的選項,是需要從資料庫裡查詢來生成options的。那麼就在model裡寫個測試方法了:

         #應該傳回一個以年份組成的二維數組

       it "should return a array by year" do  

            year = Entry.get_filter_year

            year.should be_an_instance_of(Array)

            year[0].should be_an_instance_of(Array)  

          end  

這樣,運作autotest,會報錯,Entry沒有定義get_filter_year方法,好辦啊,加上不就得了嗎。

      。。。   

。。。

      不斷的根據錯誤提示來寫功能代碼。

     。。。。

      測試終于全部通過。

      我的功能代碼也完成了。

      我對頁面的那點幻想終于成了現實。

      這就是TDD。

這個TDD的過程裡,我沒有開過浏覽器。一點不吹牛,信不信由你!

TDD的好處:

1。幫助你理清思維,去把遺留系統的需求逐漸的挖掘出來,而不用去把客戶給的三千行代碼看完。

2。驅動你的開發。整理需求寫完測試之後,然後隻需要運作autotest來利用failure資訊提示完善你的功能代碼,這個時候開發已經相當輕松了。

      3。

這樣寫的功能代碼用rcov測試test覆寫率的時候絕對是百分百覆寫的。