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

上次測試Modeul的問題還沒有解決,但是下面的還要繼續,這次來測試Controller。

1.       在test\functional目錄下,rails已經爲我們的controller生成了對應的測試文件,要注意application_controller不會生成測試文件。我們以控制登錄的LoginController爲例,打開login_controller_test.rb,內容如下:

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

require 'login_controller'

 

# Re-raise errors caught by the controller.

class LoginController; def rescue_action(e) raise e end; end

 

class LoginControllerTest < Test::Unit::TestCase

def setup

@controller = LoginController.new

@request    = ActionController::TestRequest.new

@response   = ActionController::TestResponse.new

end

# Replace this with your real tests.

def test_truth

assert true

end

end

我們看到,在setup方法裏,定義了三個對象@controller和@request和@response,這樣,我們就可以在不接入webserver或network的情況下進行測試了。

2.       我們來把其中的test_truth方法替換成下面的代碼:

def test_index

get :index

assert_response :success

end

其中,get方法模擬發出一個web請求,請求的action是index,並且捕捉響應(response),然後由assert_response斷言來判斷響應是否成功。

現在運行測試:depot>ruby test/functional/login_controller_test.rb

會看到測試失敗了,命令行的輸出:

Expected response to be a <:success>, but was <302>

1 tests, 1 assertions, 1 failures, 0 errors

爲什麼會這樣呢?回想一下,我們在前面的程序裏,在訪問index頁面時,要先判斷用戶是不是管理員。如果不是,就要跳轉到login頁面,在login_controller.rb裏:

before_filter :authorize, :except => :login

在application.rb文件裏,有authorize方法:

def authorize

unless session[:user_id]

flash[:notice] = "Please log in"

redirect_to(:controller => "login", :action => "login")

end

end

3.       好了,知道了原因,現在再寫一個測試:

def test_index_without_user

get :index

assert_redirected_to :action => "login"

assert_equal "Please log in", flash[:notice]

end

上面的代碼裏,我們嘗試請求index這個action,並且使用斷言判斷是否重定向到login,再判斷flash[:notice]裏的內容。

再次運行測試,命令行的輸出如下:

Loaded suite test/functional/login_controller_test

Started

.

Finished in 0.062 seconds.

1 tests, 3 assertions, 0 failures, 0 errors

可以看到所有的斷言都通過了。

但是還有一個問題,就是根據代碼,我們只使用了兩個斷言,但是提示信息卻顯示有三個斷言,這個問題是什麼原因還不太清楚,但是現在並不影響我們繼續下面的內容。

4.       在我們的login頁面上,用戶輸入名字和密碼後,點擊login按鈕,這些信息將會發送個login這個action,然後創建一個User的實例來讓用戶登入。

在login_controller.rb裏的login方法裏:

@user = User.new(params[:user])

logged_in_user = @user.try_to_login

現在,我們來測試login這個action,在login_controller_test.rb中添加方法:

def test_login_with_invalid_user

post :login, :user => {:name => 'fred', :password => 'opensesame'}

assert_response :success

assert_equal "Invalid user/password combination", flash[:notice]

end

大家一定看到了,這是使用了一個不存在的用戶名和密碼來測試login。

運行測試,輸出結果如下:

Finished in 0.609 seconds.

2 tests, 5 assertions, 0 failures, 0 errors

和上一個測試方法相對的,這裏代碼裏是兩個斷言,根據輸出也是兩個,挺奇怪的事情。

5.       測試了不存在的用戶,現在我們來測試用戶存在的情況。

修改fixtures目錄下的users.yml文件,我們還使用上面的用戶名和密碼:

# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html

fred:

  id: 1

  name: fred

  hashed_password: <%= Digest::SHA1.hexdigest('abracadabra') %>

然後給login_controller_test.rb添加fixtures :users,指定使用users.yml文件。

再添加方法:

def test_login_with_valid_user

post :login, :user => {:name => 'fred', :password => 'abracadabra'}

assert_redirected_to :action => "index"

assert_not_nil(session[:user_id])

user = User.find(session[:user_id])

assert_equal 'fred', user.name

end

在這裏方法裏,我們指定了和yml文件中定義的用戶名相一致的數據,並且判斷是否定位到index,再判斷用戶的id是否已經保存在session中。

根據前面測試Model時候的內容,我們在yml文件中定義的數據會被加入到數據庫中,這樣,這個方法裏的三個斷言都應該通過纔對。

OK了,運行測試,輸出結果:

Finished in 0.125 seconds.

3 tests, 8 assertions, 0 failures, 0 errors

嗯,所有的斷言都通過了。

 

好了,這次就到這裏。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章