Question

I'm a newb to rspec, mocking and stubbing. I'm slowly starting to appreciate and wrap my head around the concepts of isolated testing and mocking/stubbing in general. I have a basic question, which i think is easier explained through code:

class NewsItem < ActiveRecord::Base
  ...
  scope :ordered, order("created_at DESC")
  ...
end

In my model tests now, I wish to test the behavior that returns an ordered list of news_items. Using FactoryGirl DB-touching testing, I achieve this as follows:

# TODO use mocking and stubbing here
it "should have an ordered method to retrieve news items in the descending order" do
  news_item_x = create(:news_item, created_at: DateTime.new(2012,01,01))
  news_item_y= create(:news_item, created_at: DateTime.new(2011,01,01))
  news_item_z= create(:news_item, created_at: DateTime.new(2012,03,01))

  # .all added to avoid comparison failure between groups of NewsItem objects an ActiveRel group.
  expect(NewsItem.ordered.all).to eql([news_item_z, news_item_x, news_item_y])
end 

I'm at a loss to understand how one would convert the above tests to mocking and stubbing. Here's a first attempt, but clearly i'm misunderstanding some core concept here.

xit "should have an ordered method to retrieve news items in the descending order" do

  news_item_x = mock(NewsItem, created_at: DateTime.new(2012,01,01))
  news_item_y = mock(NewsItem, created_at: DateTime.new(2011,01,01))
  news_item_z = mock(NewsItem, created_at: DateTime.new(2012,03,01))

  NewsItem.should_receive(:ordered).and_return([news_item_z, news_item_x, news_item_y])
  # NewsItem.should_receive(:ordered).ordered # not working.

  # this is pointless as it's not checking the order of anything, just the call.
  NewsItem.ordered
end 

Is mocking/stubbing even appropriate in this kind of a test?

Any advice would be much appreciated.

VERDICT:

I got some great answers from both @arieljuod and @zetetic. To my original question, is mocking and stubbing appropriate here? The answer seems to be No as @zetetic has pointed out.

On the other hand @arieljuod gave a really nice way of actually testing my code snippet (not necessarily through mocking and stubbing). Both of these are valid answers.

Was it helpful?

Solution

Is mocking/stubbing even appropriate in this kind of a test?

No.

The point of using mocks and stubs is to isolate code that you write from its dependencies. In the case of scope, everything it depends on is buried in the Rails framework. Also, you shouldn't need to test the internals of framework/library code in the first place -- the original authors have already done that.

OTHER TIPS

You should only test that your "ordered" scopes calls "order" on the model with "created_at DESC" as the parameter, at least on that trivial example

describe 'ordered' do
  it 'orders by created_at desc' do
    NewsItem.should_receive(:order).once.with('created_at DESC')
    NewsItem.ordered
  end
end

you can trust that the query will have the order that you want

more complex scopes might need other specs, but you can always break a complex scope in smaller scopes to test them properly and only do a real database query (like you did first actually creating the objects and running the query) when the scope is not trivial (if you do some kind of weird manual sql query you should test it does what you want, otherwise, trust rails)

EDIT: as stated on the comments, that code does not work, you can check that the ActiveRelation object has the desired order set:

describe 'ordered' do
  it 'orders by created_at desc' do
    NewsItem.ordered.order_values.should == ['created_at DESC']
  end
end

that way you know that active relation will use that order on the query

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top