Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rspec: How to test recursion?

I'd like to test that a method is called recursively with a specific argument.

My approach:

class Recursable
  def rec(arg)
    rec(7) unless arg == 7
  end
end

describe Recursable do
  it "should recurse" do
    r = Recursable.new('test')
    r.should_receive(:rec).with(0).ordered
    r.should_receive(:rec).with(7).ordered
    r.rec(0)
  end
end

Unexpectedly, RSpec fails with:

expected :rec with (7) once, but received it 0 times

Any idea what's wrong with my approach? How to test for effective recursion with a specific argument?

like image 250
crispy Avatar asked Sep 01 '10 20:09

crispy


2 Answers

The problem with your test as it is now is that you are stubbing away the method you are trying to test. r.should_receive(:rec) is replacing r#rec with a stub, which of course doesn't ever call r.rec(7).

A better approach would be to simply test that the result of the initial method call is correct. It shouldn't strictly matter whether or not the method recurses, iterates, or phones a friend, as long as it gives the right answer in the end.

like image 116
Nick Lewis Avatar answered Nov 19 '22 19:11

Nick Lewis


Often if you need to test recursion it is a code smell; you probably should split the method into different responsibilities or something.

But some times you just need to add some basic checks on your recursion. You can do it with Rspec and_call_original:

it "should recurse" do
  r = Recursable.new('test')
  r.should_receive(:rec).with(0).ordered.and_call_original
  r.should_receive(:rec).with(7).ordered.and_call_original
  r.rec(0)
end

Normally should_receive will just stub the real method, that's why the recursion doesn't work. With and_call_original the stubbed method (that contains the test checks) will also call the original method implementation, that will perform the recursion as expected.

like image 29
tothemario Avatar answered Nov 19 '22 20:11

tothemario