2013-04-23 151 views
1

所以我在這裏看到了幾個與我的有點類似的問題,但還不夠近,無法幫助我弄清楚我的問題是什麼......所以對於我做錯了什麼的幫助將會是讚賞:(我下面的邁克爾·哈特爾對我已經是如何從他的例子偏離是特別有用的教程等等信息)... THXRspec測試失敗慘不忍睹

I'm throwing the following 2 errors: 

Failures: 

    1) Authentication authorization as wrong user submitting a PUT request to the Users#update action 
Failure/Error: before { put user_path(wrong_user) } 
NoMethodError: 
    undefined method `put' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_3::Nested_2::Nested_2:0x007f8943728688> 
# ./spec/features/authentication_pages_spec.rb:78:in `block (5 levels) in <top (required)>' 

2) Authentication authorization for non-signed-in users in the Users controller submitting to the update action 
Failure/Error: before { put user_path(user) } 
NoMethodError: 
    undefined method `put' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_3::Nested_1::Nested_1::Nested_2:0x007f8944a85ff0> 
# ./spec/features/authentication_pages_spec.rb:61:in `block (6 levels) in <top (required)>' 

Finished in 3.06 seconds 
56 examples, 2 failures 

Failed examples: 

rspec ./spec/features/authentication_pages_spec.rb:79 # Authentication authorization as  wrong user submitting a PUT request to the Users#update action 
rspec ./spec/features/authentication_pages_spec.rb:62 # Authentication authorization for non- signed-in users in the Users controller submitting to the update action 

我的代碼如下:

規格/功能/authentication_pages_spec.rb

require 'spec_helper' 

describe "Authentication" do 

    subject { page } 

    # FOR STATIC SIGN IN PAGE 
    describe "signin page" do 
    before { visit signin_path } 

    it { should have_selector('h1', text: 'Sign in') } 
    it { should have_title('Sign in') } 
    end 

    # FOR SIGNIN PROCESS 
    describe "signin" do 
    before { visit signin_path } 

    describe "with invalid information" do 
     before { click_button "Sign in" } 

     it { should have_title('Sign in') } 
     it { should have_error_message } 

     describe "after visiting another page" do 
     before { click_link "Home" } 
     it { should_not have_error_message } 
     end 
    end 

    describe "with valid information" do 
     let(:user) { FactoryGirl.create(:user) } 
     before { sign_in user } 

     it { should have_title(user.name) } 
     it { should have_link('Profile',  href: user_path(user)) } 
     it { should have_link('Sign out', href: signout_path) } 
     it { should have_link('Settings', href: edit_user_path(user)) } 
     it { should_not have_link('Sign in', href: signin_path) } 

     describe "followed by signout" do 
     before { click_link "Sign out" } 
     it { should have_link('Sign in') } 
     end 
    end 
    end 

    # FOR AUTHORIZING WHICH ACCOUNTS CAN DO WHAT 
    describe "authorization" do 

    describe "for non-signed-in users" do 
     let(:user) { FactoryGirl.create(:user) } 

     describe "in the Users controller" do 
     describe "visiting the edit page" do 
      before { visit edit_user_path(user) } 
      it { should have_title('Sign in') } 
     end 

     describe "submitting to the update action" do 
      before { put user_path(user) } 
      specify { response.should redirect_to(signin_path) } 
     end 
     end 
    end 

    describe "as wrong user" do 
     let(:user) { FactoryGirl.create(:user) } 
     let(:wrong_user) { FactoryGirl.create(:user, email: "[email protected]") } 
     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 

    end 
end 

我的規格/功能/ user_pages_spec.rb

require 'spec_helper' 

describe "User pages" do 

    subject { page } 

    # TESTING STATIC PROFILE PAGE 
    describe "profile page" do 
    let(:user) { FactoryGirl.create(:user) } # Code to make a user variable 
    before { visit user_path(user) } 

    it { should have_selector('h1', text: user.name) } 
    it { should have_title(user.name) } 
    end 

    # TESTING STATIC SIGNUP PAGE 
    describe "signup page" do 
    before { visit signup_path } 

    it { should have_selector('h1', text: 'Sign up') } 
    it { should have_title("Sign up") } 
    end 

    # TESTING SIGN UP PROCESS 
    describe "signup" do 
    before { visit signup_path } 

    let(:submit) { "Create my account" } 

    describe "with invalid information" do 
     it "should not create a user" do 
     expect { click_button submit }.not_to change(User, :count) 
     end 

     describe "after submission" do 
     before { click_button submit } 

     it { should have_title('Sign up') } 
     it { should have_content('error') } 
     end 
    end 

    describe "with valid information" do 
     before do 
     fill_in "Name",   with: "Example User" 
     fill_in "Email",  with: "[email protected]" 
     fill_in "Password",  with: "foobar" 
     fill_in "Confirmation", with: "foobar" 
     end 

     it "should create a user" do 
     expect { click_button submit }.to change(User, :count).by(1) 
     end 

     describe "after saving the user" do 
     before { click_button submit } 
     let(:user) { User.find_by_email('[email protected]') } 

     it { should have_title(user.name) } 
     it { should have_selector('div.alert.alert-success', text: 'Welcome') } 
     it { should have_link('Sign out') } 
     end 

    end 
    end 

    # TESTING EDITING FUNCTIONALITY 
    describe "edit" do 
    let(:user) { FactoryGirl.create(:user) } 
    before do 
     sign_in user 
     visit edit_user_path(user) 
    end 

    describe "page" do 
     it { should have_selector('h1', text: "Update your profile") } 
     it { should have_title("Edit user") } 
     # it { should have_link('change', href: 'http://gravatar.com/emails') } 
     # needed if using gravatar 
    end 

    describe "with invalid information" do 
     before { click_button "Save changes" } 

     it { should have_content('error') } 
    end 

    describe "with valid information" do 
     let(:new_name) { "New Name" } 
     let(:new_email) { "[email protected]" } 
     before do 
     fill_in "Name",    with: new_name 
     fill_in "Email",   with: new_email 
     fill_in "Password",   with: user.password 
     fill_in "Confirm Password", with: user.password 
     click_button "Save changes" 
     end 

     it { should have_title(new_name) } 
     it { should have_selector('div.alert.alert-success') } 
     it { should have_link('Sign out', href: signout_path) } 
     specify { user.reload.name.should == new_name } 
     specify { user.reload.email.should == new_email } 
    end 

    end 

end 

我的規格/支持/ utilities.rb

include ApplicationHelper 

RSpec::Matchers.define :have_error_message do |message| 
    match do |page| 
    page.has_selector?('div.alert.alert-error', text: 'Invalid') 
    end 
end 

def sign_in(user) 
    visit signin_path 
    fill_in "Email", with: user.email 
    fill_in "Password", with: user.password 
    click_button "Sign in" 
    # Sign in when not using Capybara. 
    # cookies[:remember_token] = user.remember_token 
end 

我控制器/ users_controller.rb

class UsersController < ApplicationController 
    before_filter :signed_in_user, only: [:edit, :update] 


    def new 
    @user = User.new 
    end 

    def show 
    @user = User.find(params[:id]) 
    end 

    def create 
    @user = User.new(params[:user]) 
    if @user.save 
     sign_in @user 
     flash[:success] = "Welcome to Authentication App..." 
     redirect_to @user 
    else 
     render 'new' 
    end 
    end 

    def edit 
    @user = User.find(params[:id]) 
    end 

    def update 
    @user = User.find(params[:id]) 
    if @user.update_attributes(params[:user]) 
     sign_in @user 
     flash[:success] = "Profile updated" 
     redirect_to @user 
    else 
     render 'edit' 
    end 
    end 

    def destroy 
    User.find(params[:id]).destroy 
    flash[:success] = "User destroyed" 
    redirect_to users_path 
    end 

    private 

    def signed_in_user 
     redirect_to signin_url, notice: "Please sign in." unless signed_in? 
    end 

end 

&最後我的意見/ users/edit.html.erb

<% provide(:title, "Edit user") %> 
<h1>Update your profile</h1> 

<div class="row"> 
    <div class="span6 offset3"> 
    <%= form_for(@user) do |f| %> 
     <%= render 'shared/error_messages' %> 

     <%= f.label :name %> 
     <%= f.text_field :name %> 

     <%= f.label :email %> 
     <%= f.text_field :email %> 

     <%= f.label :password %> 
     <%= f.password_field :password %> 

     <%= f.label :password_confirmation, "Confirm Password" %> 
     <%= f.password_field :password_confirmation %> 

     <%= f.submit "Save changes", class: "btn btn-large btn-primary" %> 
    <% end %> 

    </div> 
</div> 

任何和所有幫助正確的修復將不勝感激。謝謝,

回答

0

如果您正在關注Rails教程,則需要將您的Capybara版本降級到1.1.2,並將您的規格移至spec/requests目錄中。更新您的Gemfile:

gem 'capybara', '1.1.2' 

如果你打算使用水豚2.0,我建議閱讀本:

http://alindeman.github.io/2012/11/11/rspec-rails-and-capybara-2.0-what-you-need-to-know.html

+0

謝謝男人 - 看起來像屁股疼痛......所以基本上我必須回去並把所有不是水豚的測試放回到規格/要求中?但保持在/功能文件夾水豚測試? (我堅持使用新的2+水豚 - 這個鏈接非常有幫助) – BB500 2013-04-23 20:17:43

+0

如果你正在關注Michael Hartl的教程,只需將你的文件從'spec/features'移動到'spec/requests'。在GitHub上查看[sample_app](https://github.com/railstutorial/sample_app_2nd_ed)。 – 2013-04-23 20:26:39

+0

如果任何人有問題w /這些具體的錯誤......我能夠得到它/從這些傢伙的幫助答案...只需重新創建spec/requests /文件夾中的重複authentication_pages_spec.rb ...條在[描述「提交到更新操作」[測試]並將其放在新複製的文件中)。 (但不要忘了還要添加let(:user){FactoryGirl.create(:user)} – BB500 2013-04-23 20:31:14

1

put, get, post, delete和用於控制器測試的那些方法在功能測試中不可用。

在編寫功能測試時,您應該通過按鈕動作/ ajax/etc ...「提交」put,而不是像控制器測試那樣發佈到控制器。

+0

感謝權 - 所以我應該把這些測試到新目錄中。或者你能否指出我正確的方向?對不起 - 仍然很新的rspec&tdd ... – BB500 2013-04-23 19:34:02

+0

即,我可以只刪除描述「提交更新行爲」測試顯然,但我會認爲這不會是最好的主意... thx – BB500 2013-04-23 19:38:51

1

的問題是:你搞亂請求(capybara)測試與功能測試

capybara你應該描述用戶的步驟,因爲這樣的

require 'spec_helper' 

describe "Website access" do 
    context "when I am a registered user" do 
    it "should let me in" do 
     page.fill_in 'Email', with: '[email protected]' 
     page.fill_in 'Password', with: 'mydearluke' 
     page.click_link 'Let me in' 

     page.should have_content('Welcome, cheif!') 
    end 
    end 

    context "when I am not a registered user" do 
    it "should not let me in" do 
     page.fill_in 'Email', with: '[email protected]' 
     page.fill_in 'Password', with: 'wormsarmageddon' 
     page.click_link 'Let me in' 

     page.should have_content('Incorrect credentials!') 
    end 
    end  
end 

功能測試在較低的水平運行,因爲需要使用HTTP動詞putgetpostdelete與應用程序進行通信你正在測試。

require 'spec_helper' 

describe SessionsController do 
    context "when I am registered user" do 
    it "should let me in" do 
     post :create, email: '[email protected]', password: 'mydearluke' 

     response.should be_success 
    end 
    end 

    context "when I am not a registered user" do 
    it "should not let me in" do 
     post :create, email: '[email protected]', password: 'wormsarmageddon' 

     response.should_not be_success 
    end 
    end  
end 

幾件事情需要注意:

  1. 我使用post,不put
  2. 我在describe區塊中指定控制器名稱,與水豚測試中的純英文desctiption相反。
  3. 功能測試規定了如何完全是一個SessionController應該給不同的用戶憑據(它應該創造良好的用戶會話,並尖叫回到一個未註冊的)響應。

你所要做的是在你的要求(豚)測試使用動詞從功能測試。這是錯誤的。

回顧一下:

  1. 使用visitclick_link/click_buttoncapybara測試。
  2. 在功能測試中使用HTTP動詞(put,get,post, delete)。
  3. 使用devise gem進行用戶認證。
+0

我很欣賞它 - 這非常有幫助(顯然我不'有足夠的積分或東西upvote你的答案) – BB500 2013-04-23 20:19:40