Ruby cucumber advance1

出自Eddie's Courses

跳轉到: 導航, 搜尋

目錄

建立腳本

熟悉了基本篇的操作之後,接下來我們在剛剛的那個feature裡面繼續再加一個scenario,大意是要「從文章列表頁,點擊"New Article"連結後,並在Title跟Content欄位填寫文字,按下Create按鈕送出,然後會看到應該看的東西」,腳本可以這樣寫:

 Scenario: Create Article
   Given I have no articles
   And I am on the list of articles
   When I follow "New Article"
   And I fill in "Title" with "My First Title"
   And I fill in "Content" with "My First Content"
   And I press "Create"
   Then I should see "New Article Created!"
   And I should see "My First Title"
   And I should see "My First Content"
   And I should have 1 article

這看起來有點複雜,不過在cucumber/rspec裡做起來其實跟上一篇的做法差不多,就是測試、修改、再測試、再修改,有缺什麼undefined的,就補給它定義,MVC有缺的也照錯誤訊息一個一個的建立,直接全部通過為止。

開始測試

寫完腳本後,繼續重複測試的指令cucumber features:

 2 scenarios (1 undefined, 1 passed)
 14 steps (8 skipped, 2 undefined, 4 passed)
 0m0.094s

上面我省略了一些錯誤訊息,總之目前有2個scenario,14個測試裡有4個已經過了(就是我們上一篇的那4個),然後2個undefined,後面有8個先跳過,即然undefined,那我們就一樣來加一下定義吧。

錯誤訊息給的2個undefined的指示, 第一段:

  Given /^I have no articles$/ do
    pending # express the regexp above with the code you wish you had
  end

這個可以改成:

  Given /^I have no articles$/ do
    Article.delete_all
  end

就把Article model裡的東西清掉就行了,第二段:

  Then /^I should have 1 article$/ do
    pending # express the regexp above with the code you wish you had
  end

不過我們這裡做一些修改:

  Then /^I should have ([0-9]+) article$/ do |count|
    Article.count.should == count.to_i
  end

這裡把那個數字1改用RE做表示,然後去比對Article model的數字,這裡最後加了一個to_i是因為這裡當cucumber在傳參數的時候,它會以字串的方式傳進來,所以先做個轉型再來跟count做比對。

建立表單

完成定義後再跑一次測試應該會發現我們又往目標前進一步了(為了能更清楚找到錯誤的地方,下面我省略了一些比較不必要的訊息)

 When I follow "New Article"                     # features/step_definitions/web_steps.rb:26
     Could not find link with text or title or id "New Article" (Webrat::NotFoundError)
 2 scenarios (1 failed, 1 passed)
 14 steps (1 failed, 7 skipped, 6 passed)
 0m0.100s

這次的錯誤訊息是找不到"New Article"這個連結,所以我們準備就來在列表頁加個連結給它。

檔案:app/views/articles/show.html.erb

  <% for article in @articles %>
    <%=h article.title %>
  <% end %>
  <p><%= link_to "New Article", new_articles_path %></p>

連結加在哪裡都沒關係,它會自己找的到在哪。

Controller的部份也要加一下

檔案:app/controllers/articles_controller.rb

  def new
    @article = Article.new
  end

接著要來做表單的部份

檔案:app/views/articles/new.html.erb

  <% form_for @article do |f| -%>
  <p>
    <%= f.label :title %><br />
    <%= f.text_field :title %>
  </p>
  <p>
    <%= f.label :content %><br />
    <%= f.text_field :content %>
  </p>
  <p class="button"><%= f.submit "Create" %></p>
  <% end -%>

為了展示目的,基本上這裡沒用到太複雜的Rails寫法,大多是簡單的CRUD,也沒做太多的驗證跟檢查。

繼續測試

表單做好了,繼續測試流程:

And I press "Create"                            # features/step_definitions/web_steps.rb:22
     No action responded to create. Actions: index, new, and show (ActionController::UnknownAction)
 
 2 scenarios (1 failed, 1 passed)
 14 steps (1 failed, 4 skipped, 9 passed)
 0m0.124s

又少了幾個錯誤訊息了,而這次的錯誤訊息是找不到對應的action,所以接著是建立所需要的action給它。

  def create
    @article = Article.create(params[:article])
    flash[:notice] = "New Article Created!"
    redirect_to articles_path
  end

繼續測試

 And I press "Create"                            # features/step_definitions/web_steps.rb:22
   Then I should see "New Article Created!"        # features/step_definitions/web_steps.rb:142
     expected the following element's content to include "New Article Created!":
     My First Title
     New Article.
 2 scenarios (1 failed, 1 passed)
 14 steps (1 failed, 3 skipped, 10 passed)
 0m0.199s

會發現又過了一個測試,這次錯誤訊息是沒有在view看到應該要看的flash訊息跟字樣,所以接著我們修改一下show view:

檔案:app/views/articles/show.html.erb

  <p><%= flash[:notice]%></p>
  <% for article in @articles %>
    <%=h article.title %>
    <%=h article.content %>
  <% end %>
 
  <p><%= link_to "New Article", new_articles_path %></p>

一般我們應該是會把flash訊息放在layout裡,不過這裡為了展示目的就偷懶的把它隨便找個地方加一下,並且也把content欄位的東西給印出來。 再跑一下測試:

 % cucumber features
 Feature: Manage Articles
   In order to make a blog
   As an author
   I want to create and manage articles
 
   Scenario: Articles List                           # features/manage_article.feature:6
     Given I have articles titled Pizza, Breadsticks # features/step_definitions/article_steps.rb:1
     When I go to the list of articles               # features/step_definitions/web_steps.rb:18
     Then I should see "Pizza"                       # features/step_definitions/web_steps.rb:142
     And I should see "Breadsticks"                  # features/step_definitions/web_steps.rb:142
 
   Scenario: Create Article                          # features/manage_article.feature:12
     Given I have no articles                        # features/step_definitions/article_steps.rb:7
     And I am on the list of articles                # features/step_definitions/web_steps.rb:14
     When I follow "New Article"                     # features/step_definitions/web_steps.rb:26
     And I fill in "Title" with "My First Title"     # features/step_definitions/web_steps.rb:34
     And I fill in "Content" with "My First Content" # features/step_definitions/web_steps.rb:34
     And I press "Create"                            # features/step_definitions/web_steps.rb:22
     Then I should see "New Article Created!"        # features/step_definitions/web_steps.rb:142
     And I should see "My First Title"               # features/step_definitions/web_steps.rb:142
     And I should see "My First Content"             # features/step_definitions/web_steps.rb:142
     And I should have 1 article                     # features/step_definitions/article_steps.rb:11
 
 2 scenarios (2 passed)
 14 steps (14 passed)
 0m0.200s

喔!! 全部過了!!

結論

測試先行開發的原則大概就是「先寫測試 ,再寫程式」,然後邊測邊改、邊改邊測,測試通過了,你的程式也寫好了,反過來說,程式寫好了,你的測試也寫好了。TDD在網路上可以找到許多介紹它優缺點的文章,我想最大的缺點就是比一般的寫程式方法更花時間,花的時間會是原來的2倍以上(當然這也要看個人的熟練度),我個人的看法是,如果你是打算這個網站將來會長期經營維護的,前面測試所花的投資絕對是值得的。


若有任何錯誤或建議,歡迎來信指教 :)

eddie

個人工具