程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Ruby on rails開發從頭來(windows)(二十七)- 測試驅動開發

Ruby on rails開發從頭來(windows)(二十七)- 測試驅動開發

編輯:關於JAVA

在敏捷開發的實踐中,測試驅動是少不了的。這篇來看看在rails中的一個測試驅動開發的例子。

在前面我們編寫並進行了一些單元測試和功能測試,現在,我們的客戶突然要求添加一個功能:系統的每個用戶都可以對商品進行查詢。

我們先初步的畫了一些草圖,來整理我們的思路和設計,然後開始寫代碼。對於具體的實現,我們已經有了大致的思路,但是如果有更多的反饋信息的話會有助於我們走在正確的道路上。我們會在深入到代碼之前,編寫測試代碼。考慮我們的代碼將怎樣工作,確定一些規約,當測試通過,你的代碼就OK了。

現在,我們來考慮一下查詢功能的測試,應該由哪個controller來控制查詢操作呢?用戶和管理員都可以進行查詢操作,我們可以在store_controller.rb或者admin_controller.rb中添加一個search()的Action,但是這裡我們添加一個SearchController,並且含有一個方法search。在rails命令行執行命令:

depot>ruby script/generate controller Search search

我們看到,在app/controllers和test/functional目錄下已經生成了對應的文件。但是現在我們並不關心SearchController的search方法的實現,我們關心的是在測試時我們所期望看到的結果。現在添加測試代碼,在test/functional/search_controller_test.rb中添加test_search方法:

我們首先想到的是調用search的Action,然後判斷是否得到了響應:

get :search, :title => "Pragmatic Version Control"
assert_response :success

根據之前的草圖,我們應該在頁面上顯示一個flash信息,所以我們要判斷flash信息的文本,以及是否顯示了正確的頁面:

assert_equal "Found 1 product(s).", flash[:notice]
assert_template "search/results"

然後我們想要判斷查詢所得到的商品信息:

products = assigns(:products)
assert_not_nil products
assert_equal 1, products.size
assert_equal "Pragmatic Version Control", products[0].title

我們還想判斷用來顯示查詢結果的頁面的一些內容,我們查詢到的商品會作為列表在頁面上顯示,我們使用catelog視圖相同的css樣式:

assert_tag :tag => "div",
   :attributes => { :class => "results" },
   :children => { :count => 1,
   :only => { :tag => "div",
   :attributes => { :class => "catalogentry" }}}

下面是完整的測試方法:

def test_search
  get :search, :title => "Pragmatic Version Control"
  assert_response :success
  assert_equal "Found 1 product(s).", flash[:notice]
  assert_template "search/results"
  products = assigns(:products)
  assert_not_nil products
  assert_equal 1, products.size
  assert_equal "Pragmatic Version Control", products[0].title
  assert_tag :tag => "div",
   :attributes => { :class => "results" },
   :children => { :count => 1,
   :only => { :tag => "div",
   :attributes => { :class => "catalogentry" }}}
 end 

現在我們來運行測試:ruby test/functional/search_controller_test.rb

不出意外,會得到下面的結果:

test_search(SearchControllerTest) [test/functional/search_controller_test.rb:17]:
<"Found 1 product(s)."> expected but was
<nil>.1 tests, 2 assertions, 1 failures, 0 errors

因為我們還沒有設置flash的內容,進一步說,我們還沒有實現search這個Action。怎樣實現,書上給留了個作業。OK,那我們就自己來一步步實現search的Action。

1.給search方法添加內容:

@products = Product.find(:all,:conditions=>['title=?',params[:title]])
  if not @products.nil?
   flash[:notice] = sprintf('Found %d product(s).',@products.size)
  end

render(:action=>'results')現在運行測試,結果如下:

----------------------------------------------------------------------------

1) Failure:

test_search(SearchControllerTest)
  [Z:/study/ruby/InstantRails/ruby/lib/ruby/gems/1.8/gems/actionpack……
   Z:/study/ruby/InstantRails/ruby/lib/ruby/gems/1.8/gems/actionpack……
   test/functional/search_controller_test.rb:19:in `test_search']:
expecting <"search/results"> but rendering with <"search/search">
1 tests, 3 assertions, 1 failures, 0 errors

----------------------------------------------------------------------------

2.這次輪到assert_template "search/results"斷言出錯了,是因為我們還沒有results這個View,我們在view目錄下添加一個results.rhmtl文件,在search_controller.rb文件中添加一個results的空方法:

def results                
end

還要在search方法中添加一句:render("search/results"),然後再運行測試,結果如下:

----------------------------------------------------------------------------

Finished in 0.125 seconds.

1) Failure:

test_search(SearchControllerTest)
  [Z:/study/ruby/InstantRails/ruby/lib/ruby/gems/1.8/gems/…… Z:/study/ruby/InstantRails/ruby/lib/ruby/gems/1.8/gems/……
expected tag, but no tag found matching {:attributes=>{:class=>"results"}, :tag=>"div",
"<h1>Search#results</h1>\n<p>Find me in app/views/search/results.rhtml</p>\n".<nil> is not true.

----------------------------------------------------------------------------

3.現在可以看到,就只有最後一個斷言assert_tag沒有通過了,這個斷言是對頁面上的元素進行判斷的,所以我們來實現results頁面。仔細看看斷言的內容,我們就知道只要在results.rhtml裡添加兩個div就可以了,下面是results.rhtml的完整內容:

<h1>Search#results</h1>
<p>Find me in app/views/search/results.rhtml</p>
<div class="results">
  <div class = "catalogentry">
  </div>
</div>

保存,然後再運行測試,激動人心的時刻來臨了,所有的斷言都通過了!測試OK了,下面是結果:

----------------------------------------------------------

DEPRECATION WARNING: You called render('search/result……
t Z:/study/ruby/InstantRails/ruby/lib/ruby/gems/1.8/g……
Finished in 0.094 seconds.1 tests, 7 assertions, 0 failures, 0 errors

----------------------------------------------------------

4.在實現search.rhtml和results.rhtml的時候,我碰到了一些問題,用測試用例都可以選出數據來,但是通過頁面就怎麼也不行了,把log裡的sql貼出來到phpMyAdmin裡執行,也能選出數據,真不知道是怎麼回事,自己對rails的理解還不深,自己胡亂寫了這些代碼,先把代碼都帖出來,等自己對rails有更深入的理解的時候看能不能找到問題。同時也請高人指點

search_controller_test.rb:

require File.dirname(__FILE__) + '/../test_helper'
require 'search_controller'
# Re-raise errors caught by the controller.class SearchController; def rescue_action(e) raise e end; end
class SearchControllerTest < Test::Unit::TestCase
 fixtures :products
 def setup
  @controller = SearchController.new
  @request  = ActionController::TestRequest.new
  @response  = ActionController::TestResponse.new
 end
 def test_search
  get :search, :title => "Pragmatic Version Control"
  assert_response :success
  assert_equal "Found 1 product(s).", flash[:notice]
  assert_template "search/results"
  products = assigns(:products)
  assert_not_nil products
  assert_equal 1, products.size
  assert_equal "Pragmatic Version Control", products[0].title
  assert_tag :tag => "div",
   :attributes => { :class => "results" },
   :children => { :count => 1,
   :only => { :tag => "div",
   :attributes => { :class => "catalogentry" }}}
 end 
end
search_controller.rb
class SearchController < ApplicationController
 def search
  print(params[:title])
  @products = Product.find(:all,:conditions=>['title=?',params[:title]])
  if not @products.nil?
   flash[:notice] = sprintf('Found %d product(s).',@products.size)
  end
  print(flash[:notice])
  #redirect_to(:action=>'results')
  render(:action=>'results')
 end
 def results
 end
 def index
 end
end

Views下有三個文件:index.rhtml,results.rhtml,search.rhtml

index.rhtml:

<html>
<%= form_tag(:action=>'search',:id=>@products) %>
<table>
<tr>
<td>Book title:</td>
<td><%=text_field("title","")%></td>
</tr>
<tr>
<td><input type="submit" value="SEARCH" /></td>
</tr>
</table>
<%= end_form_tag %>
</html>

results.rhtml:

<h1>Search#results</h1>
<p>Find me in app/views/search/results.rhtml</p>
<div class="results">
<div class = "catalogentry">
<table cellpadding="10" cellspacing="0">
<tr class="carttitle">
<td >title</td>
<td >description</td>
<td >price</td>
</tr>
<%
printf("result:%d",@products.size)
for product in @products
-%>
<tr>
<td><%= product.title %></td>
<td><%= product.description%></td>
<td align="right"><%= fmt_dollars(product.price) %></td>
</tr>
<% end %>
</table>
</div>
</div>

search.rhtml:

<html></html>
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved