Can RSpec stubbed method return different values in sequence? Can RSpec stubbed method return different values in sequence? ruby-on-rails ruby-on-rails

Can RSpec stubbed method return different values in sequence?


You can stub a method to return different values each time it's called;

allow(@family).to receive(:location).and_return('first', 'second', 'other')

So the first time you call @family.location it will return 'first', the second time it will return 'second', and all subsequent times you call it, it will return 'other'.


RSpec 3 syntax:

allow(@family).to receive(:location).and_return("abcdefg", "bcdefgh")


The accepted solution should only be used if you have a specific number of calls and need a specific sequence of data. But what if you don't know the number of calls that will be made, or don't care about the order of data only that it's something different each time? As OP said:

simply returning different values in a sequence would be OK

The issue with and_return is that the return value is memoized. Meaning even if you'd return something dynamic you'll always get the same.

E.g.

allow(mock).to receive(:method).and_return(SecureRandom.hex)mock.method # => 7c01419e102238c6c1bd6cc5a1e25e1bmock.method # => 7c01419e102238c6c1bd6cc5a1e25e1b

Or a practical example would be using factories and getting the same IDs:

allow(Person).to receive(:create).and_return(build_stubbed(:person))Person.create # => Person(id: 1)Person.create # => Person(id: 1)

In these cases you can stub the method body to have the code executed every time:

allow(Member).to receive(:location) do  { residence: Faker::Address.city }endMember.location # => { residence: 'New York' }Member.location # => { residence: 'Budapest' }

Note that you have no access to the Member object via self in this context but can use variables from the testing context.

E.g.

member = build(:member)allow(member).to receive(:location) do  { residence: Faker::Address.city, work: member.male? 'his_work' : 'her_work' }end