I have a method which map a collection of object...
def ranking_per_lanes
all.map do |lane|
yield(lane) if block_given?
end
end
...and yield each item if a block has been passed:
def call
ranking_per_lanes do |lane|
[lane.percent, lane.tag]
end
end
# Output
[
[30, 'l2'],
[10, 'l1']
]
Here I'm trying to test call
method by mocking ranking_per_lanes
but struggle to achieve it.
I know how to mock a method in order to yield a single lane
:
allow(Lane).to receive(:ranking_per_lanes).and_yield(lane)
However, how does one reproduce what the map
block is doing ? I tried to do the following but it yield the entire collection:
allow(Lane).to receive(:ranking_per_lanes).and_yield([
FactoryBot.create(:lane, tag: 'l2', percent: 30),
FactoryBot.create(:lane, tag: 'l1', percent: 10)
])
I also tried to loop on the collection and mock it then:
[
FactoryBot.create(:lane, tag: 'l2', percent: 30),
FactoryBot.create(:lane, tag: 'l1', percent: 10)
].each do |lane|
allow(Lane).to receive(:ranking_per_lanes).and_yield(lane)
end
but it didn't work either :(
Thanks a lot for your help
CodePudding user response:
I found a solution to my problem. It is possible to stub a method with a substitue in order to pass it an internal logic. In my case, here is what I ended up doing:
before(:each) do
allow(Lane).to receive(:ranking_per_lanes) do |&block|
[
FactoryBot.create(:lane, tag: 'l2', percent: 30),
FactoryBot.create(:lane, tag: 'l1', percent: 10)
].map(&block)
end
end
which allow me to test properly my call
method:
it 'returns an array of lanes with their score' do
expect(service.send(:call)).to eq(
[
[30, 'l2'],
[10, 'l1']
]
)
end