【问题标题】:Stubbing a before_filter with RSpec使用 RSpec 存根 before_filter
【发布时间】:2010-06-11 15:36:05
【问题描述】:

我无法理解为什么我似乎无法存根这个控制器方法:load_user,因为如果我将:load_user 的实际实现更改为不返回和@user 的实例,我的所有测试都会失败。

任何人都可以看到为什么当 RSpec 向控制器发出请求时,我的存根 (controller.stub!(:load_user).and_return(@user)) 似乎无法真正被调用?

require 'spec_helper'

describe TasksController do

  before(:each) do
    @user = Factory(:user)
    sign_in @user
    @task = Factory(:task)
    User.stub_chain(:where, :first).and_return(@user)
    controller.stub!(:load_user).and_return(@user)
  end

  #GET Index
  describe "GET Index" do

    before(:each) do
      @tasks = 7.times{Factory(:task, :user => @user)}
      @user.stub!(:tasks).and_return(@tasks)
    end

    it "should should find all of the tasks owned by a user" do
      @user.should_receive(:tasks).and_return(@tasks)
      get :index, :user_id => @user.id
    end

    it "should assign all of the user's tasks to the view" do
      get :index, :user_id => @user.id
      assigns[:tasks].should be(@tasks)      
    end
  end

  #GET New
  describe "GET New" do

    before(:each) do
      @user.stub_chain(:tasks, :new).and_return(@task)
    end

    it "should return a new Task" do
      @user.tasks.should_receive(:new).and_return(@task)
      get :new, :user_id => @user.id
    end
  end

  #POST Create
  describe "POST Create" do

    before(:each) do
      @user.stub_chain(:tasks, :new).and_return(@task)
    end

    it "should create a new task" do
     @user.tasks.should_receive(:new).and_return(@task)
      post :create, :user_id => @user.id, :task => @task.to_s
    end

    it "saves the task" do
      @task.should_receive(:save)
      post :create, :user_id => @user.id, :task => @task
    end

    context "when the task is saved successfully" do

      before(:each) do
        @task.stub!(:save).and_return(true)
      end

      it "should set the flash[:notice] message to 'Task Added Successfully'"do 
        post :create, :user_id => @user.id, :task => @task
        flash[:notice].should == "Task Added Successfully!"
      end

      it "should redirect to the user's task page" do
        post :create, :user_id => @user.id, :task => @task
        response.should redirect_to(user_tasks_path(@user.id))
      end
    end

    context "when the task isn't saved successfully" do

      before(:each) do
        @task.stub(:save).and_return(false)
      end

      it "should return to the 'Create New Task' page do" do
        post :create, :user_id => @user.id, :task => @task
        response.should render_template('new')
      end
    end
  end

  it "should attempt to authenticate and load the user who owns the tasks" do

    context "when the tasks belong to the currently logged in user" do

      it "should set the user instance variable to the currently logged in user" do
        pending 
      end

    end

    context "when the tasks belong to another user" do

      it "should set the flash[:notice] to 'Sorry but you can't view other people's tasks.'" do
        pending
      end

      it "should redirect to the home page" do
        pending
      end
    end
  end
end

class TasksController < ApplicationController
  before_filter :load_user 

  def index
    @tasks = @user.tasks
  end

  def new
    @task = @user.tasks.new
  end

  def create
    @task = @user.tasks.new
    if @task.save
      flash[:notice] = "Task Added Successfully!"
      redirect_to user_tasks_path(@user.id)
    else
      render :action => 'new'
    end
  end

  private

  def load_user
    if current_user.id == params[:user_id].to_i
      @user = User.where(:id => params[:user_id]).first 
    else
      flash[:notice] = "Sorry but you can't view other people's tasks."
      redirect_to root_path
    end
  end
end

谁能看到为什么我的存根不起作用?就像我说的,我的测试只有在我确保 load_user 工作时才能通过,如果没有,我的所有测试都会失败,这让我认为 RSpec 没有使用我创建的存根。

【问题讨论】:

  • 对不起,我没有真正的答案,但请确保您在测试中存根的控制器和实际执行代码的控制器是同一个实例。您可以查看他们的object_id 以确保。

标签: ruby-on-rails unit-testing rspec stub


【解决方案1】:

存根 load_user 会破坏您的测试,因为存根方法会使它中性化。当控制器调用load_user 时,它不再运行您的原始代码。它现在只是返回您在and_return(...) 中指定的任何内容(返回到ActionController 回调堆栈,它会忽略false 以外的任何内容)。

您的控制器代码没有使用该方法的返回值;它使用实例化的变量 within。由于load_user 方法的原始代码没有运行,@user 实例变量永远不会被实例化。 (您的测试中的 @user 变量仅对您的测试可见。)

但是对于您拥有的所有其他存根,我看不出有任何理由需要将load_user 存根。只要您将current_user 存根以返回@user(我假设这是在sign_in 方法中完成的),那么就不应该有任何需要。

【讨论】:

  • 这是一个很好的解释,如果我能投票更多,我会的。非常感谢,关于返回 @user 与实例化 @user 的解释确实帮助我点击了。
【解决方案2】:

您还可以尝试通过执行类似断言来验证存根是否有效

controller.current_user.should == @user

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多