[rspec-users] how to test named_scope

David Chelimsky dchelimsky at gmail.com
Tue Oct 12 02:37:12 EDT 2010


On Wed, Oct 6, 2010 at 12:44 PM, Cyrus <cyruscavalcante at gmail.com> wrote:
> how a can test this controller using rspec
>
> #home controller
>  def home
>      @recents = Article.publisheds.with_authorship.paginate(:page => 1, :per_page => 10, :total_entries => 10)
>      @highlight = Article.publisheds.highlight.with_authorship
>  end

You can do this with stub_chain, but I would not recommend it:

describe "GET home" do
  it "assigns recent articles to @recents" do
    recent = mock_model(Article)
    Article.stub_chain("publisheds.with_authorship.paginate") { [recent] }
    assigns(:recents).should eq(recents)
  end

  it "assigns the highlight to @highlight" do
    highlight = mock_model(Highlight)
    Article.stub_chain("publisheds.highlight.with_authorship") { highlight }
    assigns(:highlight).should eq(highlight)
  end
end

Instead, I'd recommend using the spec (written _first_) to drive out
simpler APIs on Article.

describe "GET home" do
  before do
    Article.stub(:recents)
    Article.stub(:highlight)
  end

  it "assigns recent articles to @recents" do
    recents = [mock_model(Article)]
    Article.stub(:recents) { recents }
    get :home
    assigns(:recents).should eq(recents)
  end

  it "paginates the recent articles" do
    recents = [mock_model(Article)]
    recents.should_receive(:paginate).with(:page => 1, :per_page =>
10, :total_entries => 10)
    get :home
  end

  it "assigns the highlight to @highlight" do
    highlight = mock_model(Highlight)
    Article.stub(:highlight) { highlight }
    assigns(:highlight).should eq(highlight)
  end
end

Now the controller code gets a bit simpler:

def home
  @recents = Article.recents.paginate(:page => 1, :per_page => 10,
:total_entries => 10)
  @highlight = Article.highlight
end

And the examples specify the assorted responsibilities.

Now you can spec the recents and highlight methods on the Article
model, but instead of mentioning the named scopes and trying to stub
everything that happens internally on Article, just set up the example
data that you need:

describe "recents" do
  it "includes articles written within the past two weeks" do
    too_old = Factory(:article, :published_at => 15.days.ago)
    just_young_enough = Factory(:article, :published_at => 14.days.ago)
    more_than_young_enough = Factory(:article, :published_at => 13.days.ago)
    Article.recents.should =~ [just_young_enough, more_than_young_enough]
  end
end

etc, etc.

This way the responsibilities are nicely separated, the surface area
between the controller and the model is smaller and more targeted, and
you are free to refactor Article below a simpler API.

HTH,
David

>
>
> #article model
>
>  named_scope :publisheds, lambda { { :conditions => ["published_at
> <= ? and status = 'publicado'", Time.now.utc] } }
>  named_scope :highlight, lambda { { :conditions => ["highlight IS NOT
> NULL and highlight <> ''"],  :order => "highlight desc, published_at
> desc", :limit => 4 } }
> named_scope :with_authorship, :include => [:authorships, :authors]
>
>
> i do this bat dont work:
>
>
> describe GeneralController do
>  def mock_article(stubs={})
>    @mock_article ||= mock_model(Article, stubs)
>  end
>
>  describe "GET index" do
>    it "should expose article as @articles" do
>      articles = [mock_article]
>      Article.should_receive(:publisheds).and_return(articles)
>      articles.should_receive(:with_authorship).and_return(articles)
>      articles.should_receive(:paginate).with(:per_page =>
> 10,:total_entries=>10, :page => 1).and_return(articles)
>      get :home
>      assigns[:recents].should == articles
>    end
> end
> end


More information about the rspec-users mailing list