Mocking and stubbing Rails' association extensions

I’m having a lot of trouble stubbing out an association extension for
some view tests. Example rails code modeling a music album:

class Album < ActiveRecord::Base
has_many :songs do
def streamable
find(:all, :conditions => ‘streamable = 1’)
end
end
end

So for a given Album instance (say @album), I need to be able to stub
both @album.songs and @album.songs.streamable in the same before block.

Is there a way for a stub to return one thing when called alone
(@album.songs) and another stub when the call is chained?
(@album.songs.streamable)

Before adding the extension, I just had @album.songs returning an
array of Song instances. The only thing I’ve thought of that would
work is temporarily extending Array itself to respond to #streamable,
but that feels ugly.

Thanks for any ideas,

Chris K.

On Jan 10, 2008 12:35 PM, Chris K. [email protected] wrote:

but that feels ugly.
album = mock(“album”)
songs = mock(“songs”)
album.stub!(:songs).and_return(songs)
songs.stub!(:streamable).and_return(true)

That’s the general idea. Specifics will vary for each example.

Cool?

On 1/10/08, David C. [email protected] wrote:

album = mock(“album”)
songs = mock(“songs”)
album.stub!(:songs).and_return(songs)
songs.stub!(:streamable).and_return(true)

That’s the general idea. Specifics will vary for each example.

If I do this, I end up with a mock object when I call @album.songs. I
need
that object to act like a Rails association – so it should respond to
#each, #first, and all our other Enumerable friends, since my view
iterates
over it, as well as the stubbed call to #streamable, which returns a
“filtered” version of the assocation (see Rails code in OP). But I
certainly
don’t want to start stubbing Enumerable methods.

Let’s say song1, song2, and song3 are instances of Song.

Song has a boolean attribute, streamable.

song1.streamable? => true

song2.streamable? => true

song3.streamable? => false

album = mock(“album”)
songs = mock(“songs”)
album.stub!(:songs).and_return(songs)
songs.stub!(:streamable).and_return([song1, song2])

So now album.songs.streamable returns [song1, song2] – perfect. But I
need
album.songs to return [song1, song2, song3] as well. That’s the problem.

I hope that’s a little clearer. Thanks for the help.

Chris

On 1/10/08, Chris K. [email protected] wrote:

that object to act like a Rails association – so it should respond to
album = mock(“album”)
songs = mock(“songs”)
album.stub!(:songs).and_return(songs)
songs.stub!(:streamable).and_return([song1, song2])

So now album.songs.streamable returns [song1, song2] – perfect. But I need
album.songs to return [song1, song2, song3] as well. That’s the problem.

So why not

songs = [song1, song2, song3]
album.stub!(:songs).and_return(songs)
songs.stub!(:streamable).and_return([song1, song2])


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On 1/10/08, Rick DeNatale [email protected] wrote:

So why not

songs = [song1, song2, song3]
album.stub!(:songs).and_return(songs)
songs.stub!(:streamable).and_return([song1, song2])

Oh, of course. Thank you.

I think my mind was in a rut of “must use mock or mock_model” and I
didn’t
think to just stub a method call on an existing array.

Chris