Expecting arbitrary method calls in a particular order

I’ve been wondering how to expect arbitrary methods being called in a
particular order. The RSpec documentation for expecting method calls
on mock objects mentions that it is possible to pass a block to
#should_receive, but does not mention that it can be used to track the
method call order pretty easily:

http://www.artweb-design.de/2008/7/13/expecting-arbitrary-method-calls-in-a-particular-order-in-rspec

Is there a better way of doing this?

If not, do you think it would make sense to add this to the RSpec
docs? http://rspec.info/documentation/mocks/message_expectations.html


sven fuchs [email protected]
artweb design http://www.artweb-design.de
grünberger 65 + 49 (0) 30 - 47 98 69 96 (phone)
d-10245 berlin + 49 (0) 171 - 35 20 38 4 (mobile)

On Sun, Jul 13, 2008 at 9:49 AM, Sven F. [email protected]
wrote:

If not, do you think it would make sense to add this to the RSpec docs?
http://rspec.info/documentation/mocks/message_expectations.html

Hey Sven,

Mock objects have an optional notion of ordering. Check out the
following spec:

describe “a mock object” do
it “should expect ordered messages” do
foo = mock(“ordered mock”)
foo.should_receive(:first).ordered
foo.should_receive(:second).ordered
foo.should_receive(:third).ordered

foo.first
foo.second
foo.third

end
end

Changing the order in which they’re called will raise an
ExpectationNotMetError.

Pat

On Sun, Jul 13, 2008 at 9:32 AM, Pat M. [email protected] wrote:

foo.should_receive(:first).ordered
foo.should_receive(:second).ordered
foo.should_receive(:third).ordered

foo.first
foo.second
foo.third
end
end

Changing the order in which they’re called will raise an ExpectationNotMetError.

Sven, FYI - this is explained on the page you mentioned:
http://rspec.info/documentation/mocks/message_expectations.html

Cheers,
David

On 13.07.2008, at 17:01, Sven F. wrote:

calls on mock
If not, do you think it would make sense to add this to the RSpec
foo = mock(“ordered mock”)
Changing the order in which they’re called will raise an
In Pat’s spec above the methods #first, #second and #third are
Now, when the filter_chain is run I want to expect that the filters
order of messages sent to a mock")

Am I missing something?

Maybe it’s bit more clear this way:

class Chain < Array
def run
each{|object| object.run}
end
end

describe “Expecting the order of methods being called on arbitrary
objects” do
it “works” do
first = mock(‘first’)
second = mock(‘second’)

 chain = Chain.new
 chain << first
 chain << second

 second.should_receive(:run).ordered
 first.should_receive(:run).ordered
 chain.run

end
end

This passes, of course.

I’d want to to specify that first#run is run first and second#run is
run second though and I think I can’t do that with
should_receive.ordered


sven fuchs [email protected]
artweb design http://www.artweb-design.de
grünberger 65 + 49 (0) 30 - 47 98 69 96 (phone)
d-10245 berlin + 49 (0) 171 - 35 20 38 4 (mobile)

On 13.07.2008, at 16:41, David C. wrote:

order pretty
Hey Sven,

http://rspec.info/documentation/mocks/message_expectations.html
Hey guys, thanks for the quick answers :slight_smile:

Maybe I was not clear enough about what I wanted to spec. Or I
actually do not understand what #ordered does.

In Pat’s spec above the methods #first, #second and #third are called
on the same object foo and the spec defines the order. That’s kind of
the opposite of my usecase. I wanted to specify that the a method #run
(or whatever) is called on different objects in a particular order.
Like:

filter_1 = mock(‘filter_1’)
filter_2 = mock(‘filter_2’)
filter_chain << filter_1
filter_chain << filter_2

Now, when the filter_chain is run I want to expect that the filters
are run in the order they were added to the chain:

filter_chain.run
methods_called_on_individual_filters.should == [‘filter_1#run’,
‘filter_2#run’] # pseudo-code

If that’s possible somehow with should_receive(:run).ordered than at
least it’s not very clear from that docs page which only talks about
expecting the order of methods being called on the same mock, not on
different mocks. (“There are times when you want to specify the order
of messages sent to a mock”)

Am I missing something?


sven fuchs [email protected]
artweb design http://www.artweb-design.de
grünberger 65 + 49 (0) 30 - 47 98 69 96 (phone)
d-10245 berlin + 49 (0) 171 - 35 20 38 4 (mobile)

On Jul 13, 2008, at 4:35 pm, Sven F. wrote:

second.should_receive(:run).ordered
first.should_receive(:run).ordered
chain.run
end
end

Hi Sven

I think you want

second.should_receive(:run) do
first.should_receive(:run)
end

which, if Mail.app is running my specs correctly, should only pass if
second receives :run before first

Is that what you were after?

Ashley


http://www.patchspace.co.uk/

Hey Ashley!

How’s things? :slight_smile:

On 13.07.2008, at 17:44, Ashley M. wrote:

I think you want

second.should_receive(:run) do
first.should_receive(:run)
end

which, if Mail.app is running my specs correctly, should only pass
if second receives :run before first

Is that what you were after?

Wow, yes.

This also uses the block passed to should_receive, but in a nicer way
than my inital attemp which is a bit chatty.

It’d look a bit odd when I want to specify the order for a bunch of
methods, but actually I don’t need to do that here.

Again, this really should be documented. I even started digging into
the RSpec source, but obviously lacked the creativity for this :slight_smile:


sven fuchs [email protected]
artweb design http://www.artweb-design.de
grünberger 65 + 49 (0) 30 - 47 98 69 96 (phone)
d-10245 berlin + 49 (0) 171 - 35 20 38 4 (mobile)

You want cross mock ordering! I’ve wanted this in RSpec in the past as
well.
The only ruby-based mocking library I know of that does this is
Hardmock. It
looks like its RDoc now has instructions for it to work with RSpec:

http://hardmock.rubyforge.org/

Zach

On Sun, Jul 13, 2008 at 11:35 AM, Sven F.
[email protected]

Hi Zach,

On 13.07.2008, at 17:59, Zach D. wrote:

You want cross mock ordering! I’ve wanted this in RSpec in the past
as well. The only ruby-based mocking library I know of that does
this is Hardmock. It looks like its RDoc now has instructions for it
to work with RSpec:

http://hardmock.rubyforge.org/

Thanks for the suggestion!

To be honest, I’m not eager to add another library. Ashley’s approach
seems to work fine and I only need it in a couple of specs.

On Sun, Jul 13, 2008 at 9:32 AM, Pat M. [email protected] wrote:

Mock objects have an optional notion of ordering. Check out the
foo.second
Hey guys, thanks for the quick answers :slight_smile:
filter_1 = mock(‘filter_1’)

class Chain < Array

This passes, of course.
grünberger 65 + 49 (0) 30 - 47 98 69 96 (phone)


Zach D.
http://www.continuousthinking.com


rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users


sven fuchs [email protected]
artweb design http://www.artweb-design.de
grünberger 65 + 49 (0) 30 - 47 98 69 96 (phone)
d-10245 berlin + 49 (0) 171 - 35 20 38 4 (mobile)

On Jul 13, 2008, at 5:03 pm, Sven F. wrote:

Hey Ashley!

How’s things? :slight_smile:

Good thanks, just sadly not spent much time using RSpec lately…

Spam me off list if you want to catch up!

Wow, yes.

This also uses the block passed to should_receive, but in a nicer
way than my inital attemp which is a bit chatty.

It’d look a bit odd when I want to specify the order for a bunch of
methods, but actually I don’t need to do that here.

Again, this really should be documented. I even started digging into
the RSpec source, but obviously lacked the creativity for this :slight_smile:

I remember posting about this a long time ago. I think it was Aslak
that replied. I’d prefer a neater syntax for ordered expectations
across mocks. Not too long ago I was working on my database migration
tool that has to turn a graph of migrations into a linear sequence
before it can apply them, and obviously the order is essential. But
the specs look something like…

migration_1.should_receive(:apply) do
migration_2.should_receive(:apply) do
migration_3.should_receive(:apply) do
migration_4.should_receive(:apply) do

which is a bit hideous.

I’d prefer something like

migration_1.should_receive(:apply)

migration_2.should_receive(:apply).after(migration_2.receives(:apply))

but I guess that would complicate the implementation.

As it’s a relatively uncommon thing I think probably just documenting
it is ok for now.

Ashley


http://www.patchspace.co.uk/