2012-06-12 45 views
14

Lưu ý: Tôi đã đọc câu hỏi và câu trả lời this, nhưng vì một số lý do mã không hoạt động đối với tôi. (xem bên dưới để biết lỗi tôi nhận được)Phương pháp tiêu diệt thử nghiệm RSpec (Hướng dẫn Rails 3.2 Ch. 9, Ví dụ 10)

Bài tập 10 từ Chương 9 của Hướng dẫn Rails yêu cầu bạn: Sửa đổi hành động phá hủy [đối với người dùng] để ngăn người dùng quản trị tự hủy. (Viết một bài kiểm tra đầu tiên.)

Phần khó khăn ở đây là thử nghiệm nó, vì ứng dụng đã ẩn liên kết "xóa" cho người dùng hiện tại, vì vậy bạn phải thực hiện yêu cầu http trực tiếp.

Tôi nhận mã hoạt động và thử nghiệm mã bằng cách xóa đoạn mã ẩn liên kết xóa cho người dùng hiện tại. Chắc chắn, nếu tôi nhấp vào liên kết xóa cho người dùng hiện đã đăng nhập, nó sẽ chuyển hướng tôi và cung cấp cho tôi thông báo thông báo.

Từ users_controller.rb

def destroy 
    @user = User.find(params[:id]) 
    if current_user?(@user) 
     redirect_to users_path, notice: "You can't destroy yourself." 
    else 
     @user.destroy 
     flash[:success] = "User destroyed." 
     redirect_to users_path 
    end 
    end 

Vấn đề tôi đang gặp là bằng văn bản cho các bài kiểm tra cho điều này mà sẽ gửi yêu cầu xóa và gọi phá hủy phương pháp. Tôi đã thử các giải pháp từ Rspec test for destroy if no delete link, mà tôi đang sao chép ở đây:

Từ user_pages_spec.rb

describe "destroy" do 
    let(:admin) { FactoryGirl.create(:admin) } 

    it "should not allow the admin to delete herself" do 
     sign_in admin 
     #expect { delete user_path(admin), method: :delete }.should change(User, :count) 
     expect { delete :destroy, :id => admin.id }.should_not change(User, :count) 
    end 
    end 

Nhưng khi tôi chạy này, tôi nhận được lỗi này từ RSpec

Failures: 

    1) User Pages destroy should not allow the admin to delete herself 
    Failure/Error: expect { delete :destroy, :id => admin.id }.should_not change(User, :count) 
    ArgumentError: 
     bad argument (expected URI object or URI string) 
    # ./spec/requests/user_pages_spec.rb:180:in `block (4 levels) in <top (required)>' 
    # ./spec/requests/user_pages_spec.rb:180:in `block (3 levels) in <top (required)>' 

Vì vậy, câu hỏi của tôi là: 1) Tại sao mã này ở trên không thành công? 2) Làm cách nào để mô phỏng "xóa" để gọi hành động hủy trong bộ điều khiển của tôi?

Môi trường: Mac OSX ruby ​​1.9.3p194 Rails 3.2.3

Gems để thử nghiệm:
nhóm: kiểm tra làm đá quý 'rspec-ray', '2.9.0' đá quý 'Capybara ',' 1.1.2 ' đá quý' rb-fsevent ',' 0.4.3.1 ',: require => false gem' growl ',' 1.0.3 ' gem' guard-spork ',' 0.3.2 ' 'spork' đá quý ',' 0.9.0 ' đá quý' factory_girl_rails ',' 1.4.0 ' kết thúc

Thông tin khác Tôi đã thử một số ton cách cố gắng mô phỏng nhấp vào liên kết xóa và không có cách nào hoạt động. Tôi đã sử dụng gem debugger để xem phương thức destroy có được gọi hay không. Trong bài kiểm tra đó nhấp chuột vào đường dẫn để xóa một người dùng khác nhau, phá hủy phương pháp được gọi và nó hoạt động tốt:

it "should be able to delete another user" do 
    expect { click_link('delete') }.to change(User, :count).by(-1) 
end 

Nhưng không có gì tôi đã cố gắng tạo ra yêu cầu xóa trực tiếp đã làm việc để gọi phá hủy phương pháp.

Cảm ơn sự giúp đỡ của bạn!

Will

** CẬP NHẬT **

Tôi cố gắng gợi ý DVG của:

describe "destroy" do 
    let(:admin) { FactoryGirl.create(:admin) } 

    it "should not allow the admin to delete herself" do 
     sign_in admin 
     #expect { delete user_path(admin), method: :delete }.should change(User, :count) 
     expect { delete :destroy, :id => admin }.to_not change(User, :count) 
    end 
    end 

Và nhận lỗi này:

6) User Pages destroy should not allow the admin to delete herself 
    Failure/Error: expect { delete :destroy, :id => admin }.to_not change(User, :count) 
    ArgumentError: 
     bad argument (expected URI object or URI string) 
    # ./spec/requests/user_pages_spec.rb:190:in `block (4 levels) in <top (required)>' 
    # ./spec/requests/user_pages_spec.rb:190:in `block (3 levels) in <top (required)>' 

SOLUTION

Tôi đã tìm ra sau FOREVER.

Tôi đã phải sử dụng Rack :: Test để đưa ra yêu cầu DELETE, nhưng Capybara và Rack :: Test không chia sẻ cùng một MockSession, vì vậy tôi đã phải lấy: remember_token và:! Sample_app_session cookie và đặt chúng vào yêu cầu DELETE theo cách thủ công. Đây là những gì đã làm việc. (Vấn đề khác mà tôi đã có, được liệt kê dưới đây, là tôi đã có một tuyên bố force_ssl mà không để cho hành động phá hoại của tôi được gọi.

describe "destroy" do 
    let!(:admin) { FactoryGirl.create(:admin) } 

    before do 
     sign_in admin 
    end 

    it "should delete a normal user" do 
     user = FactoryGirl.create(:user) 
     expect { delete user_path(user), {}, 
     'HTTP_COOKIE' => "remember_token=#{admin.remember_token}, 
     #{Capybara.current_session.driver.response.headers["Set-Cookie"]}" }. 
     to change(User, :count).by(-1) 
    end 

    it "should not allow the admin to delete herself" do 
     expect { delete user_path(admin), {}, 
     'HTTP_COOKIE' => "remember_token=#{admin.remember_token}, 
     #{Capybara.current_session.driver.response.headers["Set-Cookie"]}" }. 
     to_not change(User, :count) 
    end 
    end 

Tôi đã có một tuyên bố force_ssl sau before_filters tôi trong users_controller.rb tôi và điều này được bằng cách nào đó ném vật tắt vì vậy tôi không bao giờ có hành động tiêu diệt.

class UsersController < ApplicationController 
    before_filter :signed_in_user, only: [:edit, :update, :index] 
    before_filter :existing_user, only: [:new, :create] 
    before_filter :correct_user, only: [:edit, :update] 
    before_filter :admin_user,  only: :destroy 

    #force_ssl 

    def index 
    @users = User.paginate(page: params[:page]) 
    end 

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

    def destroy 
    @user = User.find(params[:id]) 
    if current_user?(@user) 
     redirect_to users_path, notice: "You can't destroy yourself." 
    else 
     @user.destroy 
     flash[:success] = "User destroyed." 
     redirect_to users_path 
    end 
    end 

Đây là những hữu ích trong việc đến một giải pháp

https://gist.github.com/484787

http://collectiveidea.com/blog/archives/2012/01/05/capybara-cucumber-and-how-the-cookie-crumbles/

+0

Một điều tôi chỉ phát hiện ra, đó không phải là vấn đề của tôi chính xác nhưng có thể được * một vấn đề * là phương pháp let là lười biếng, vì vậy tôi có thể tưởng tượng nó Screwing lên mong đợi to_not thay đổi chức năng. Vì vậy, tôi điều chỉnh mã để sử dụng cho phép! khi tạo người dùng quản trị. –

+0

kịch bản bạn đang thử nghiệm là gì? Nhật ký quản trị trong, xóa liên kết bị ẩn, nhưng bằng cách nào đó, anh ấy đã xử lý yêu cầu xóa? (chỉ cần hỏi) –

+0

Câu hỏi hay. Chủ yếu câu trả lời là đây là một bài tập trong Hướng dẫn Rails. Hóa ra đó là một bài tập tốt, bởi vì tôi đã học được mọi thứ về cookie, yêu cầu http, Capybara và Rack :: Test. Tôi cho rằng tôi có thể kiểm tra kịch bản mà mã để ẩn liên kết xóa không thành công và tôi muốn bộ điều khiển của mình có một bản sao lưu. –

Trả lời

5

Bạn đang bối rối-ray rspec thông số kỹ thuật theo yêu cầu đó là những thử nghiệm tích hợp và được thực hiện trong một số kỹ thuật trình duyệt và điều khiển mô phỏng mà thử nghiệm điều khiển trong sự cô lập. delete(action, *args) (và get, post và vân vân) - là một phương thức mô phỏng yêu cầu từ ActionController :: TestCase, vì vậy nó không có sẵn trong thử nghiệm của bạn.

Vì vậy, tùy chọn duy nhất của bạn là mô phỏng nhấp chuột trong trình duyệt. Tôi không biết làm thế nào bạn ẩn liên kết xóa của bạn, nếu html là có nhưng ẩn bạn sẽ có thể nhấp vào nó. Nếu nó không có ở đó (được xóa ở phía máy chủ khi tạo chế độ xem), bạn có thể sử dụng sốcủa capybara (nhưng bạn phải bật javascript cho ví dụ này :js => true). Bạn có thể thêm liên kết lại:

page.execute_script("$('body').append("<a href="https://stackoverflow.com/users/1" data-method="delete" rel="nofollow">Destroy</a>")") 

hoặc thực hiện cuộc gọi ajax:

page.execute_script("$.ajax({type:'DELETE',url:'/users/1'})") 

Không kiểm tra nhưng một cái gì đó như thế này nên làm việc.

3

Hãy thử điều này:

expect { delete :destroy, :id => admin }.to_not change(User, :count) 
+0

Đã thử nó, cùng một lỗi (xem ở trên) –

+0

Điều này làm việc cho tôi. Cảm ơn! –

6

tôi giải quyết vấn đề này tương tự sử dụng như sau:

describe "should not be able to delete themselves" do 
    it { expect { delete user_path(admin) }.not_to change(User, :count) } 
end 
+1

Tôi nghĩ rằng điều này chỉ hoạt động trong các bài kiểm tra điều khiển, không phải thử nghiệm tích hợp. – Dean

+0

Bài kiểm tra này vượt qua, mặc dù tôi đã kiểm tra thủ công và nó không hoạt động. (nó sẽ thất bại) –

6

giải pháp CallumD của làm việc cho tôi, và dường như phù hợp nhất với các kỹ thuật được đề nghị trong phần còn lại của hướng dẫn Michael Hartl của.Nhưng tôi muốn thắt chặt cú pháp một chút để làm cho nó phù hợp hơn với các thông số kỹ thuật khác trong cùng một hướng dẫn:

it "should not be able to delete itself" do 
    expect { delete user_path(admin) }.not_to change(User, :count) 
end 
+1

Tôi đồng ý. Tôi làm giống vậy. – KMcA

5

Đây là những gì tôi đã kết thúc với (RSpec 3.2):

describe 'DELETE destroy' do 
    before :each do 
    delete :destroy, { id: current_partner_role } 
    end 

    it 'destroys role' do 
    expect(assigns(:role).destroyed?).to be true 
    end 

"bị phá hủy?" phương pháp chính nó là spec-ed bởi Rails vì vậy IMHO nó sẽ là ok để dựa vào nó.

https://github.com/rails/rails/blob/5142d5411481c893f817c1431b0869be3745060f/activerecord/lib/active_record/persistence.rb#L91

Các vấn đề liên quan