2009-12-18 59 views
8

測試控制器的實例變量我有一個末日應用程序,如果用戶登錄,供應頁面爲只讀或可編輯根據。與機架::測試和西納特拉

控制器設置一個變量@can_edit,即由視圖使用來隱藏/顯示編輯鏈接。如何在我的測試中測試@can_edit的值?我不知道如何獲取Rack :: Test下的控制器當前實例。

我用class_eval存根在控制器中logged_in?方法,但我不得不求助於檢查last_response.body我的編輯鏈接以查看是否@can_edit已設置與否。

如何直接測試@can_edit的值?

回答

8

不幸的是,如果不修改Rack :: Test,我不認爲這是可能的。當您在應用程序測試的請求時,機架::測試包括以下內容:

  1. 添加請求最近請求列表
  2. 創建應用程序的新實例,並調用其call方法
  3. 將您的應用程序對最近回覆列表

可以很容易地訪問響應last_requestlast_response,但遺憾的是沒有任何信息被保存了您的應用程序的狀態,而這是runni NG。

如果您有興趣一起測試Rack :: Test補丁,請在第30行查看rack-test/lib/rack/mock_session.rb。這是Rack :: Test運行您的應用程序並接收標準Rack應用程序返回值(狀態,標題,正文)。我的猜測是,你將不得不修改你的應用程序,以收集和訪問它的所有實例變量。

在任何情況下,最好測試結果,而不是實施細節。如果你想確保編輯鏈接是不可見的,通過DOM ID的編輯鏈接的存在測試:

assert last_response.body.match(/<a href="..." id="...">/) 
+0

「最好測試結果,而不是實現細節」我以前見過類似的聲明,我不同意。如果你想要2,1 + 1工作的很好,但1 + 2 + 10 - 11也是如此。這兩者都不意味着你的應用程序「實際工作正常」。 – nowk 2009-12-18 17:14:07

+1

但是,我並不完全不同意你的看法:假設有一種方法執行不正確。如果方法在100%的時間內返回正確的答案(你不能想到失敗的情況),那麼實現是否真的「不正確?」有關係嗎? 如果您發現自己正在測試方法中的變量值,則可能沒有足夠的測試用例(輸入)。如果您重命名變量或以其他方式更改應用程序的實現而不更改其行爲,則應該通過測試而不做任何修改。這是首先使用測試的重要原因。 – 2009-12-18 17:52:36

+0

我認爲測試@can_edit正在測試控制器的輸出。我不喜歡通過檢查視圖來設置@can_edit時發生的情況來間接測試它。這應該是一個不同的測試,完全是爲了這個觀點。 – Brian 2009-12-21 14:25:30

4

有可能有一點的黑客。 Sinatra應用程序的實例不可用,因爲它們是在調用Sinatra :: Base#調用時創建的。如亞歷克斯解釋。這個黑客準備了一個實例,讓下一個呼叫抓住它。

require 'something/to/be/required' 

class Sinatra::Base 
    @@prepared = nil 

    def self.onion_core 
    onion = prototype 
    loop do 
     onion = onion.instance_variable_get('@app') 
     return onion if onion.class == self || onion.nil? 
    end 
    end 

    def self.prepare_instance 
    @@prepared = onion_core 
    end 

    # Override 
    def call(env) 
    d = @@prepared || dup 
    @@prepared = nil 
    d.call!(env) 
    end 
end 

describe 'An Sinatra app' do 
    include Rack::Test::Methods 

    def app 
    Sinatra::Application 
    end 

    it 'prepares an app instance on ahead' do 
    app_instance = app.prepare_instance  
    get '/foo' 
    app_instance.instance_variable_get('@can_edit').should be_true 
    end 
end 

我首先想到了這種技術到mock the instance that runs the current test

+0

這會爲我返回nil app_instance。可能是最新的Sinatra改變了它的基礎班。 – gpavlidi 2013-01-18 01:25:51

0

繼承人討厭的,但可行的替代

# app.rb - sets an instance variable for all routes 
before do 
    @foo = 'bar' 
end 

# spec.rb 
it 'sets an instance variable via before filter' do 
    my_app = MySinatraApplication 
    expected_value = nil 
    # define a fake route 
    my_app.get '/before-filter-test' do 
    # as previously stated, Sinatra app instance isn't avaiable until #call is performed 
    expected_value = @foo 
    end 
    my_app.new.call({ 
    'REQUEST_METHOD' => 'GET', 
    'PATH_INFO' => '/before-filter-test', 
    'rack.input' => StringIO.new 
    }) 
    expect(expected_value).to eq('bar') 
end 

這使您可以對測試之前基本應用程序創建的過濾器和或訪問實例變量西納特拉。