2014-02-19 62 views
3

我期待有用戶只能刪除自己創建的作業(而不是他人的作業)。我已經驗證我的應用程序是通過「rails server」來完成的。然而,測試出現怪異。RSpec錯誤的行爲期望更改計數與銷燬

這裏是有問題的測試:

require 'spec_helper' 

describe "Authentication" do 
    subject { page } 

    describe "signin" do 
    [...] 

    describe "authorization" do 
     [...] 

     describe "correct user control" do 
     let(:user) { FactoryGirl.create(:user) } 
     let(:job) { FactoryGirl.create(:job, user: user) } 
     let(:wrong_user) { FactoryGirl.create(:user, email: "[email protected]") } 
     let(:wrong_job) { FactoryGirl.create(:job, user: wrong_user) } 
     before { sign_in user } 
     [...] 
     describe "users can only delete their own jobs" do 
      it "should not change job count" do 
      expect do 
       delete job_path(wrong_job) 
      end.to_not change(Job, :count) 
      end 
     end 
     describe "users can delete their own jobs" do 
      it "should decrease job count" do 
      expect do 
       delete job_path(job) 
      end.to change(Job, :count).by(-1) 
      end 
     end 
     end 
    end 
    end 
end 

除此之外,我得到這個奇怪的輸出:

失敗:

1) Authentication signin authorization correct user control users can only delete their own jobs should not decrease job count 
    Failure/Error: expect do 
     count should not have changed, but did change from 0 to 1 
    # ./spec/requests/authentication_pages_spec.rb:68:in `block (6 levels) in <top (required)>' 

    2) Authentication signin authorization correct user control users can delete their own jobs should decrease job count 
    Failure/Error: expect do 
     count should have been changed by -1, but was changed by 1 
    # ./spec/requests/authentication_pages_spec.rb:75:in `block (6 levels) in <top (required)>' 

爲什麼作業計數增加嗎?爲什麼測試不按預期工作?


其他信息:

jobs_controller.rb

class JobsController < ApplicationController 
    skip_before_action :require_signin, only: [:index, :show] 
    skip_before_action :correct_user, only: [:index, :show, :new, :create] 
    before_action :set_job, only: [:show, :edit, :update, :destroy] 

    [...] 

    def destroy 
    @job.destroy 
    respond_to do |format| 
     format.html { redirect_to jobs_url } 
     format.json { head :no_content } 
    end 
    end 

    private 
    def set_job 
     @job = Job.find(params[:id]) 
    end 

    def job_params 
    params.require(:job).permit(:title, :org, :internship, :postdate, :filldate, :location, :link, :description) 
    end 
end 

application_controller.rb

class ApplicationController < ActionController::Base 
    protect_from_forgery with: :exception 
    before_filter :require_signin 
    before_filter :correct_user 

    include SessionsHelper 

    private 
    def require_signin 
     unless signed_in? 
     store_location 
     redirect_to signin_url, notice: "Please sign in." 
     end 
    end 

    def correct_user 
     @job = current_user.jobs.find_by(id: params[:id]) 
     redirect_to root_url if @job.nil? 
    end 
end 

耙路線

Prefix Verb URI Pattern    Controller#Action 
     jobs GET /jobs(.:format)   jobs#index 
      POST /jobs(.:format)   jobs#create 
    new_job GET /jobs/new(.:format)  jobs#new 
    edit_job GET /jobs/:id/edit(.:format) jobs#edit 
     job GET /jobs/:id(.:format)  jobs#show 
      PATCH /jobs/:id(.:format)  jobs#update 
      PUT /jobs/:id(.:format)  jobs#update 
      DELETE /jobs/:id(.:format)  jobs#destroy 
[...] 

回答

3

有兩個問題:

  1. 正如亞切克提到,let是懶洋洋地評估。這意味着在使用該變量之前,塊內的代碼不會運行。由於在expect塊內第一次使用job變量,所以job計數增加。如果要使let塊內的代碼立即運行,請使用let!方法。

  2. getputpatchdelete應在控制器測試,而不是集成測試使用:

 
# jobs_controller_spec.rb 
delete :destroy, id: job 

在集成測試,你應該使用水豚來模擬用戶輸入:

# users_messing_around_with_jobs_spec.rb 
click_button("Delete") 

在您的測試中,delete沒有達到您的預期:由於某種原因,它已被映射到jobs#index

2

試試吧!而不是讓因爲簡單的「讓」被懶惰評估。我的意思尤其是這兩條線:

let!(:job) { FactoryGirl.create(:job, user: user) }   
let!(:wrong_job) { FactoryGirl.create(:job, user: wrong_user) } 
0

讓我們先來檢查我們的命名路由:

我們沒有找到一個名爲路線的delete動作,所以delete job_path(wrong_job)delete job_path(job)如我們預期不會刪除作業。 相反,由於兩個delete job_path(wrong_job)delete job_path(job)執行延遲評估it塊中的jobwrong_job,所以對於每個測試,Job模型對象總是會更改1。

這裏有兩個選項來解決這個問題:

  1. 創建一個名爲路線delete行動。
  2. 添加一個ID以指定應刪除哪項工作,例如:delete :destroy, id: job.id

第一篇文章,讓我知道如果它是不正確的。

+0

感謝您對懶惰評估的見解。 我重寫了測試作爲控制器測試,它效果更好。 – peterhurford