3

私はRuby on Rails チュートリアルに従っていますが、認証コードのテストを作成する必要があります。たとえば、ユーザーが自分のプロファイルのみを編集できるようにするなどです。

テストするアクションは 2 つあります。1 つは、ユーザーが他のユーザーのプロファイルを編集するページにアクセスできないようにすることです。これは簡単で、カピバラでの単純な「機能」テストです。

しかし、ユーザーが編集ページをバイパスして PUT 要求を手動で送信できないように、PUT アクションもテストしたいと思います。私が読んだことから、これはrspecの「リクエスト」テストとして行う必要があります。

今私の質問は、それらを別のディレクトリに維持する必要がありますか? (仕様/機能対仕様/要求)? これら 2 つのシナリオは密接に関連しているため、正しくないように思えます。このようなテストは通常​​、Rails でどのように行われますか?

例えば、

describe "as wrong user" do
  let(:user) { FactoryGirl.create(:user) }
  let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }
  before { sign_in user }

  describe "visiting Users#edit page" do
    before { visit edit_user_path(wrong_user) }
    it { should_not have_selector('title', text: full_title('Edit user')) }
  end

  describe "submitting a PUT request to the Users#update action" do
    before { put user_path(wrong_user) }
    specify { response.should redirect_to(root_path) }
  end
end

「put」がサポートされなくなったため、2 番目のテストは capybara 2.x では機能しません。リクエストテストでなければなりません。そして今、2 つ目の "sign_in" メソッドを作成する必要があります。これは、現在のメソッドが機能テストでのみ使用できるメソッドを使用しているためです。多くのコードの重複のようなにおいがします。

========私の解決策========

Paul Fioravanti の回答のおかげで、リクエスト テストにログインする方法を見つけた後、

    before do
      post sessions_path, email: user.email, password: user.password
      cookies[:remember_token] = user.remember_token
    end

すべてのテストを要求テストに変更しました。したがって、それらを別のファイルに分割する必要はありません。これはよりクリーンだと思いますが、ポールのソリューションも機能します。

describe 'authorization' do
  describe 'as un-signed-in user' do
    let(:user) { FactoryGirl.create(:user) }

    describe 'getting user edit page' do
      before { get edit_user_path(user) }

      specify { response.should redirect_to(signin_path) }
    end

    describe 'putting to user update page' do
      before { put user_path(user) }

      specify { response.should redirect_to(signin_path) }
    end
  end

  describe 'as wrong user' do
    let(:user) { FactoryGirl.create(:user) }
    let(:wrong_user) { FactoryGirl.create(:user, email: 'wrong@example.com') }

    before do
      post sessions_path, email: user.email, password: user.password
      cookies[:remember_token] = user.remember_token
    end

    describe 'getting user edit page' do
      before { get edit_user_path(wrong_user) }

      specify { response.should redirect_to(root_path) }
    end

    describe 'putting to user update page' do
      before { put user_path(wrong_user) }

      specify { response.should redirect_to(root_path) }
    end
  end
end
4

2 に答える 2

2

Railsチュートリアルを終了し、サンプルアプリをCapybara 2.0にアップグレードした後、リクエストと機能の仕様を分割するという骨の折れるプロセスを経ることになりました。現在もチュートリアルを行っているとのことなので、Hartlが指定するgem(Capybara 1.1.2)を維持し、サンプルアプリを完成させてから、リファクタリングとしてリクエスト/機能の問題に戻ることをお勧めします。エクササイズ。参考までに、これが私の「間違ったユーザー」の承認仕様を書くことになった方法です。

spec / support / Utilities.rb

def sign_in_through_ui(user)
  fill_in "Email",    with: user.email
  fill_in "Password", with: user.password
  click_button "Sign In"
end

def sign_in_request(user)
  post session_path(email: user.email, password: user.password)
  cookies[:remember_token] = user.remember_token
end

RSpec::Matchers::define :have_title do |text|
  match do |page|
    Capybara.string(page.body).has_selector?('title', text: text)
  end
end

spec / features / authentication_pages_spec.rb

describe "Authentication on UI" do

  subject { page }
  # ...
  describe "authorization" do
    # ...
    context "as a wrong user" do
      let(:user)       { FactoryGirl.create(:user) }
      let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }

      before do
        visit root_path
        click_link "Sign In"
        sign_in_through_ui(user)
      end

      context "visiting Users#edit" do
        let(:page_title) { full_title("Edit User") }
        before { visit edit_user_path(wrong_user) }
        it { should_not have_title(page_title) }
      end
    end
  end
end

spec / requests / authentication_requests_spec.rb

describe "Authentication Requests" do

  subject { response }
  # ...
  describe "authorization" do
    # ...
    context "as a wrong user" do
      let(:user)       { FactoryGirl.create(:user) }
      let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }

      before { sign_in_request(user) }

      context "PUT Users#update" do
        before { put user_path(wrong_user) }
        it { should redirect_to(root_url) }
      end
    end

  end
end

feature仕様を仕様から分離する方法を理解しようとするとき、私は主に次の2つのリンクを参照として使用しましたrequest

アップデート:

カスタムRSpecマッチャーが必要ない場合は、上記のテストで以下を使用して、title要素で同じ結果を取得することもできます。

its(:source) { should have_selector('title', text: page_title) }
于 2013-02-17T05:21:45.983 に答える