blog.sorah.jp

rspec-mock broken by `scope :public` in ActiveRecord::Base

class Foo < ActiveRecord::Base
  scope :public, -> { … } # this overrides Module#public
end

class FoosController < ApplicationController
  def create
    @foo = Foo.new(params[:foo])

    respond_to do |format|
      if @foo.save
        format.html { redirect_to @foo, notice: 'foo was successfully created.' }
        format.json { render json: @foo, status: :created, location: @foo }
      else
        format.html { render action: "new" }
        format.json { render json: @foo.errors, status: :unprocessable_entity }
      end
    end
  end
end

describe FoosController do
  describe "POST create" do
    describe "with invalid params" do
      it "re-renders the 'new' template" do
        # rspec-mock expects Foo.public to `Module#public`
        Foo.any_instance.stub(:save).and_return(false)

        post :create, {:foo => {}}, valid_session
        response.should render_template("new")
      end
    end
end

scope :public overrides Module#public method in the model, but rspec-mock expects Foo.public to be Module#public. rspec-mock calls Foo.public with arguments, so it raises ArgumentError on line scope :public. :/

 ArgumentError:
   wrong number of arguments (1 for 0)

こんな感じで scope :public, -> {…} していると、rspec-mock が Module#public(*name) を期待して引数付きで public を呼んで崩壊する模様。

Foo を stub ってるせいでテストがコケるみたいです。

Backfilled at , Published at