Rack::Test と Sinatra を使用したコントローラーのインスタンス変数のテスト
質問
ユーザーがログインしているかどうかに応じて、ページを読み取り専用または編集可能として提供する Sinatra アプリがあります。
コントローラーが変数を設定する @can_edit
, 、編集リンクを表示/非表示にするためにビューによって使用されます。どうすればテストできますか @can_edit
私のテストにおける の値は?Rack::Test の下にあるコントローラーの現在のインスタンスを取得する方法がわかりません。
私が使う class_eval
をスタブする logged_in?
コントローラーのメソッドですが、チェックする必要があります last_response.body
編集リンクについては、 @can_edit
設定されているかどうか。
の値をテストするにはどうすればよいですか @can_edit
直接?
解決
残念ながら、Rack::Test を変更しない限りこれは不可能だと思います。アプリケーションのテスト中にリクエストを行うと、Rack::Test は次のことを行います。
- 最近のリクエストのリストにリクエストを追加します
- アプリケーションの新しいインスタンスを作成し、そのインスタンスを呼び出します
call
方法 - アプリケーションの応答を最近の応答のリストに追加します
アクセスは簡単です last_request
そして last_response
, ただし、残念ながら、アプリケーションの実行中の状態に関する情報は保存されません。
これを行うために Rack::Test パッチをハッキングすることに興味がある場合は、まず以下を見てください。 rack-test/lib/rack/mock_session.rb
30行目。ここで、Rack::Test はアプリケーションを実行し、標準の Rack アプリの戻り値 (ステータス、ヘッダー、本文) を受け取ります。私の推測では、すべてのインスタンス変数を収集してアクセスできるようにするには、アプリケーションも変更する必要があると思います。
いずれの場合も、実装の詳細ではなく、結果をテストすることが最善です。編集リンクが表示されていないことを確認したい場合は、DOM ID で編集リンクの存在をテストします。
assert last_response.body.match(/<a href="..." id="...">/)
他のヒント
これは少しハックで可能です。シナトラ::ベース#コールが呼び出されたときにそれらが作成されるため、シナトラアプリのインスタンスは使用できません。アレックスは説明したように。このハックは先に、インスタンスを作成し、次の呼び出しは、それをつかむせます。
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
私はに最初の場所で現在のテストを実行し、インスタンスをあざけり、この手法を考え出しました。
相続人は嫌なしかし現実的な代替
# 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
これはフィルタの前シナトラに対してテストおよびまたはベースアプリケーション用に作成されたインスタンス変数にアクセスすることができます。