我希望用户只能删除他们自己创建的作业(而不是其他人的作业)。我已通过" rails server"验证我的应用确实这样做了。然而,测试结果很奇怪。
以下是有问题的测试:
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: "wrong@example.com") }
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
[...]
答案 0 :(得分:5)
有两个问题:
正如Jacek所说,let
被懒惰地评估。这意味着在使用变量之前,块中的代码不会运行。由于job
块中首次使用expect
变量,因此job
计数会增加。如果您希望立即运行let
块中的代码,请使用let!
方法。
get
,put
,patch
和delete
应该用于控制器测试,而不是集成测试:
# jobs_controller_spec.rb delete :destroy, id: job
在集成测试中,您应该使用Capybara来模拟用户输入:
# users_messing_around_with_jobs_spec.rb
click_button("Delete")
在您的测试中,delete
没有达到您所期望的效果:由于某种原因,它已映射到jobs#index
。
答案 1 :(得分:3)
试试吧!而不是让因为简单的“让”是惰性评估的。我的意思是这两行:
let!(:job) { FactoryGirl.create(:job, user: user) }
let!(:wrong_job) { FactoryGirl.create(:job, user: wrong_user) }
答案 2 :(得分:0)
让我们先检查我们的命名路线:
我们未找到delete
操作的命名路由,因此delete job_path(wrong_job)
和delete job_path(job)
不会按预期删除该作业。
相反,由于两个delete job_path(wrong_job)
和delete job_path(job)
执行延迟评估了每个job
块中的wrong_job
和it
,因此Job模型对象将始终更改每次测试为1。
有两种方法可以解决这个问题:
delete
操作创建命名路由。delete :destroy, id: job.id
。首先发帖,如果不正确,请告诉我。